Quantcast
Browsing Latest Articles All 41 Live
Mark channel Not-Safe-For-Work? (0 votes)
Are you the publisher? or about this channel.
No ratings yet.
Articles:

【PHP8.0】PHPでunion型が使えるようになる

Union Types 2.0というRFCが投票中です。
提案者はまたまたのNikita。
2019/10/25開始、2019/11/08終了で、受理には2/3+1の賛成が必要です。
2019/11/04時点で賛成55反対5であり、ほぼ導入確定です。

PHPのunion型って何かというと、TypeScriptのunion型とだいたい同じです。
int|string $aと書いたら$aint型もしくはstring型ですよ、ということです。

ちなみに別途RFCをGitHubで管理しようという実験が進行中で、このRFCの詳細はGitHub上に存在します
このRFCはまだNikitaの個人GitHub上にしかないのですが、本決まりになったらPHP公式に移動になると思います。
まあGitHubのほうが管理とか更新とか楽ですからね。
ただGitHubはURLがすぐ404になるのだけはどうにかしてほしい。

Union Types 2.0

Introduction

union型は、単一の型ではなく、複数の異なる型の値を受け入れます。
PHPは既に、2種類の特別なunion型をサポートしています。

・null許容型。?Tで使える。
・array型もしくはTraversable型。iterableで使える。

しかし任意のunion型はサポートされていません。
現在はかわりにphpdoc注釈を書くくらいしかできません。

classNumber{/**
     * @var int|float $number
     */private$number;/**
     * @param int|float $number
     */publicfunctionsetNumber($number){$this->number=$number;}/**
     * @return int|float
     */publicfunctiongetNumber(){return$this->number;}}

Statisticsセクションで、オープンソースでunion型がどれだけ普及しているかを示しています。

言語でunion型をサポートすることにより、より多くの型情報をphpdocに頼ることなく関数シグナチャに移動することができ、多数の利点が得られます。

・型は実際に強制されるため、ミスを早期に発見できる。
・エッジケースを見逃したり、仕様変更の際にドキュメントを更新し忘れたりする可能性が減る。
・継承時にもリスコフの置換原則を適用できる。
・リフレクションから利用できる。
・phpdocより分量が減らせる。

union型は、ジェネリクスと並んで型システムに残っている最大の穴です。

Proposal

union型を構文T1|T2|...で表し、型を書くことができる全ての位置でunion型を使用可能とする。

classNumber{privateint|float$number;publicfunctionsetNumber(int|float$number):void{$this->number=$number;}publicfunctiongetNumber():int|float{return$this->number;}}

Supported Types

union型は、現在PHPでサポートされている全ての型をサポートしますが、一部の型については注意が必要です。

void型

void型は、union型の一部となることは決してできません。
T|voidのような型は、戻り値を含む全ての位置で不正です。

void型は関数に戻り値がないことを表します。
あらゆる非void型と互換がありません。

かわりにnull許容型?Tがあり、これはT型もしくはnullを返すことができます。

null許容型

T1|T2|nullとしてnullを許容するunion型を定義することができます。
既存の?Tは、T|nullの省略形と見做されます。

このRFCの草稿では、null許容型の文法が2種類になることを防ぐため、?(T1|T2)という文法を提唱していました。
しかしこの構文は都合が悪く、さらにphpdocで確立されているT1|T2|null構文とも異なっています。
議論の結果は、T1|T2|nullの文法が圧倒的に優勢でした。
?TT|nullの省略形として今後も有効な構文で、推奨も非推奨もされず、当分は廃止される予定もありません。

null型は、union型の一部としてのみ有効な型で、単独で使うことはできません。

union型と?T表記を混ぜて使用することはできません。
?T1|T2T1|?T2?(T1|T2)は全て不正な文法で、この場合はT1|T2|nullを使う必要があります。

false疑似型

現在では、エラーや不正が起きた際の関数の戻り値はnullにすることが推奨されていますが、歴史的理由から多くの内部関数はfalseを返してきます。
Statisticsセクションで示すように、union型を返す内部関数は大部分がfalseを含んでいます。

一般的な例としてはint|falseを返すstrposなどです。
これを正しく表記するとint|boolですが、これは関数がtrueを返すこともあるという誤った印象を与えます。

そのため、このRFCにはfalseのみを表すfalse疑似型が含まれています。
trueのみを表すtrue疑似型は、それが必要となる歴史的理由が存在しないため、このRFCには含まれません。

false疑似型は、union型の一部としてのみ有効で、単独やnull許容型として使うことはできません。
falsefalse|null?falseは全て無効な構文です。

Duplicate and redundant types

クラスのロードを行わずに検出できる冗長な記述は、コンパイルエラーになります。
これは以下のような例を含みます。

・同じ型の重複。int|string|INTは不可。
boolにはfalseを追加できない。
objectには個別のクラス型を追加できない。
iterableにはarrayTraversableを追加できない。

これは、型が最小であることを保証はしません。
たとえばクラスAとBがクラスエイリアスや継承関係にある場合、A|Bは有効です。

functionfoo():int|INT{}// ×functionfoo():bool|false{}// ×useAasB;functionfoo():A|B{}// × 構文解析時点でわかるclass_alias('X','Y');functionfoo():X|Y{}// 許可 実行時までわからない

Type grammar

特殊なvoid型を除くと、型の構文は以下のようになります。

type: simple_type
    | "?" simple_type
    | union_type
    ;

union_type: simple_type "|" simple_type
          | union_type "|" simple_type
          ;

simple_type: "false"          # union型でのみ有効
           | "null"           # union型でのみ有効
           | "bool"
           | "int"
           | "float"
           | "string"
           | "array"
           | "object"
           | "iterable"
           | "callable"       # プロパティ型指定では無効
           | "self"
           | "parent"
           | namespaced_name
           ;

Variance

union型は、既存の型ルールに従います。
・戻り値は共変。
・パラメータ型は反変。
・プロパティ型は不変。

唯一の変更点は、union型が派生型と相互作用する点であり、そのため3つの追加ルールがあります。

・全てのU_iV_jのサブタイプであった場合、U_1|...|U_nV_1|...|V_mのサブタイプである。
iterablearray|Traversableと同じと見做す。
・false疑似型はboolのサブタイプと見做す。

以下において、許可されているものと許可されないものの例を幾つか示します。

Property types

プロパティの型は不変です。
すなわち、継承しても型は同じである必要があります。
ただし、この"同じ"は意味が同じということを表します。
これまでもクラスエイリアスで同じクラスを表す別名を付けることができました。

union型はこの"同じ"の範囲を広げ、たとえばint|stringstring|intは同じとして扱います。

classA{}classBextendsA{}classTest{publicA|B$prop;}classTest2extendsTest{publicA$prop;}

この例では、親クラスのA|B型と子クラスのA型は明らかに異なる型であるにもかかわらず、これは正当な文法です。
内部的には、以下のようにこの結果に到達します。
まず、それはAのサブタイプであるため、AA|Bのサブタイプです。1
次にAAのサブタイプであり、BAのサブタイプであるため、A|BAのサブタイプです。

Adding and removing union types

戻り値からunion型の一部を削除し、パラメータに一部の型を追加することは正しい文法です。

classTest{publicfunctionparam1(int$param){}publicfunctionparam2(int|float$param){}publicfunctionreturn1():int|float{}publicfunctionreturn2():int{}}classTest2extendsTest{publicfunctionparam1(int|float$param){}// OK: パラメータの型追加は許可publicfunctionparam2(int$param){}// NG: パラメータの型削除は禁止publicfunctionreturn1():int{}// OK: 返り値の型削除は許可publicfunctionreturn2():int|float{}// NG: 返り値の型追加は禁止}

Variance of individual union members

同様に、戻り値の型を狭めたり、パラメータの型を広げることは許可されます。

classA{}classBextendsA{}classTest{publicfunctionparam1(B|string$param){}publicfunctionparam2(A|string$param){}publicfunctionreturn1():A|string{}publicfunctionreturn2():B|string{}}classTest2extendsTest{publicfunctionparam1(A|string$param){}// OK: BをAに広げたpublicfunctionparam2(B|string$param){}// NG: AをBに狭めたpublicfunctionreturn1():B|string{}// OK: AをBに狭めたpublicfunctionreturn2():A|string{}// NG: BをAに広げた}

もちろん同じことを複数のunion型に同時に行ったり、型の追加削除と型の拡縮を組み合わせることもできます。

Coercive typing mode

strict_typesが有効でない場合、スカラー型宣言は暗黙の型変換の対象となります。
これは一部のunion型において、変更先の型を一意に決められないため問題となります。
たとえばint|stringfalseを渡すと、0""の両方が暗黙の型変換の候補になります。

従って、引数に正しくないスカラー値が渡ってきた場合、以下の優先順位で変換することにします。

1.int
2.float
3.string
4.bool

PHPの既存の型変換機構で型変換が可能である場合、その型が選ばれます。

例外として、値が文字列であり、union型がint|floatである場合、優先される型は引数の数値文字列の中身によって決まります。
すなわち、"42"はint型となり、"42.0"はfloat型となります。

上記のリストに含まれない型には自動型変換されません。
特にnullfalseへの自動型変換は起きないことに注意しましょう。

// int|string42-->42// 正しい型"42"-->"42"// 正しい型newObjectWithToString-->"__toString()の結果"// objectはint型にならない42.0-->42// floatはint型になる42.1-->42// floatはint型になる1e100-->"1.0E+100"// floatの上限を超えたらstring型になるINF-->"INF"// floatの上限を超えたらstring型になるtrue-->1// boolはint型になる[]-->TypeError// 配列はint|string型にならない// int|float|bool"45"-->45// 整数っぽいのでint型になる"45.0"-->45.0// 小数っぽいのでfloat型になる"45X"-->45+Notice:Nonwellformednumericstring// 有効部分は整数っぽいのでint型になり、E_NOTICEが出る""-->false// 数値形式文字列でないのでbool型になる"X"-->true// 数値形式文字列でないのでbool型になる[]-->TypeError// 配列はint|float|bool型にならない

Alternatives

自動型変換については、別案が2種類ありました。

ひとつめはunion型は常に厳密な型指定とすることで、複雑な強制型変換を完全に排除することです。
これは2つの欠点があります。
まず、strictでないときに型をfloatからfloat|intにすると、直感に反して有効な入力が減ります。
第二に、float型float|int型のサブタイプと言えなくなるため、union型のモデルが崩壊します。

二つ目が、変換の優先順位を型の順番にすることです。
これは即ちint|stringstring|intが異なる型になることを意味します。
この変換は直感的ではなく、継承関係に非常に不明瞭な影響を及ぼします。

Property types and references

union型プロパティへの参照は、プロパティ型指定RFCに書かれた挙動に従います。
プロパティ型指定とunion型の組み合わせによる影響は、当時から考慮されていました

classTest{publicint|string$x;publicfloat|string$y;}$test=newTest;$r="foobar";$test->x=&$r;$test->y=&$r;// $rと$test->xと$test->yは同じもので、型は{ mixed, int|string, float|string }の論理積になる$r=42;// TypeError

複数のリファレンスが紐付けられている場合、型の強制変換が行われた後の最終的な型は全ての型と互換する必要があります。
上記例の場合、$test->xはint型の42になり、$test->yはfloat型の42.0になります。
これは同じ型ではないため、TypeErrorが投げられます。

この場合は共通の型であるstring型にキャストすることでエラーは出なくなりますが、自動型変換による優先順位と異なるため、型がどうなるかわからないという欠点があります。

Reflection

union型をサポートするReflectionUnionTypeクラスが追加されます。

classReflectionUnionTypeextendsReflectionType{/** @return ReflectionType[] */publicfunctiongetTypes();/* Inherited from ReflectionType *//** @return bool */publicfunctionallowsNull();/* Inherited from ReflectionType *//** @return string */publicfunction__toString();}

getTypes()メソッドは、ReflectionTypeクラスの配列を返します。
この型は、元の型宣言と順番が異なる可能性があり、また等価である別の型になる可能性があります。

たとえばint|string型が["string", "int"]の順で要素を返す場合があります。
またiterable|array|string型は["iterable", "string"]になるかもしれないし["Traversable", "array", "string"]になるかもしれません。
Reflection APIが保証するのは、論理的に同じものであるということです。

allowsNull()メソッドは、union型の要素にnull型が含まれるか否かを返します。

__toString()メソッドは、型宣言を有効なコード表現として返します。
元の型宣言と必ずしも同じではありません。

後方互換性のため、null許容型?TT|nullのunion型は、ReflectionUnionTypeではなくReflectionNamedTypeを返します。

// getTypes()や__toString()の結果は順番が異なることもあるfunctiontest():float|int{}$rt=(newReflectionFunction('test'))->getReturnType();var_dump(get_class($rt));// "ReflectionUnionType"var_dump($rt->allowsNull());// falsevar_dump($rt->getTypes());// [ReflectionType("int"), ReflectionType("float")]var_dump((string)$rt);// "int|float"functiontest2():float|int|null{}$rt=(newReflectionFunction('test2'))->getReturnType();var_dump(get_class($rt));// "ReflectionUnionType"var_dump($rt->allowsNull());// truevar_dump($rt->getTypes());// [ReflectionType("int"), ReflectionType("float"), ReflectionType("null")]var_dump((string)$rt);// "int|float|null"functiontest3():int|null{}$rt=(newReflectionFunction('test3'))->getReturnType();var_dump(get_class($rt));// "ReflectionNamedType"var_dump($rt->allowsNull());// truevar_dump($rt->getName());// "int"var_dump((string)$rt);// "?int"

Backwards Incompatible Changes

このRFCには、後方互換性のない変更はありません。
ただしReflectionTypeを利用しているコードは、union型に関する処理を追加する必要があります。

Future Scope

この項目は今後の展望であり、このRFCには含まれていません。

Intersection Types

交差型は論理的にunion型と似ています。
union型では少なくとも一つの型が満たされる必要がありますが、交差型では全ての型が満たされる必要があります。

たとえばTraversable|CountableTraversableCountableのうち少なくともどちらかである必要がありますが、Traversable&CountableTraversableでありなおかつCountableである必要があります。

Mixed Type

mixed型は、任意の値が受け入れ可能であることを表します。
型指定が無い場合と見た目の動きは同じですが、型指定が無いと、それが本当に自由であるのか、単に型指定を書き忘れただけなのかが区別できません。

Literal Types

このRFCで導入されたfalse疑似型は、TypeScriptでサポートされているリテラル型の特殊なケースです。
リテラル型は、列挙型のように一部特定の値のみを許可できる型です。

typeArrayFilterFlags=0|ARRAY_FILTER_USE_KEY|ARRAY_FILTER_USE_BOTH;array_filter(array$array,callable$callback,ArrayFilterFlags$flag):array;

列挙型ではなくリテラル型を使用する利点は、元の文法をそのまま維持できることです。
そのため、後方互換性を壊すことなく後付けすることができます。

Type Aliases

型が複雑になると、型宣言の再利用が必要になります。
その一般的な方法は2種類が考えられます。
ひとつめは次のようなエイリアスです。

useint|floatasnumber;functionfoo(number$x){}

このnumber型はソースコード上でのみ現れる型で、コンパイル時に元のint|floatに解決されます。

もうひとつは型宣言を定義することです。

namespaceFoo;typenumber=int|float;// \Foo\numberをどこからでも使える

Statistics

上位2000パッケージの@param@returnにおいて、野生のunion型がどれだけ使われているかを分析しました。

@paramのunion型:25k。一覧
@returnのunion型:14k。一覧

PHPの内部関数を調べたところ(調査が不完全なので最低2倍はあるはず)

・336関数がunion型を返す。
・そのうち213関数がfalse型を返す。

多くの内部関数が、戻り値の型を表すためにfalse疑似型が必要であることを示しています。

感想

元々型に厳密なTypeScriptがunion型を導入する理由はまあわかるんですよ。
しかしですね、元々フリーダム型だったPHPがわざわざ型宣言やらプロパティ型指定やらで狭めてきた上でのunion型って、なんというかこうマッチポンプ感とかそんな感じを感じざるをえない。
いやまあ違う話だってのは理屈ではわかるんですけど感覚的にね。

PHPにおいてこの機能の使い道は、DateTime|falsearray|nullといった、失敗時に例外を出さず無効値を返す関数の呼び出しにほぼ限られるでしょう。
あとは$_REQUESTを受け取るときのint|stringくらいでしょうか。
PDO|GMPなんて書いてきた人がいたら、設計をどうにかしろと突っ返します。

PHPでunion型をうまく使う方法、正直あまり思いつきません。
誰かがきっといいサンプルを考えてくれるはず。


  1. itがどれにかかってるのかわからなかった。というかここの文の意味がわからん。 

RFCのbibtexを生成するコマンドが便利なので全てのX論生に届け

概要

  • 小ネタ
  • インターネットな論文を書くとき,ちょくちょくRFCを引用する.
  • IETF Draft(RFC)のbibtexをささっと生成するコマンドがあるから紹介したい

本題: rfcbibtex

PyPi: https://pypi.org/project/rfcbibtex/
Github: https://github.com/iluxonchik/rfc-bibtex/

使用例

こんな感じで使える.簡単.

~/
$ rfcbibtex RFC8215
@misc{RFC8215,
        series =        {Request for Comments},
        number =        8215,
        howpublished =  {RFC 8215},
        publisher =     {RFC Editor},
        doi =           {10.17487/RFC8215},
        url =           {https://rfc-editor.org/rfc/rfc8215.txt},
        author =        {Tore Anderson},
        title =         {{Local-Use IPv4/IPv6 Translation Prefix}},
        pagetotal =     7,
        year =          2017,
        month =         aug,
        abstract =      {This document reserves the IPv6 prefix 64:ff9b:1::/48 for local use within domains that enable IPv4/IPv6 translation mechanisms.},
}

生成したいRFCを複数書いたテキストファイルも参照できる

rfc.txt
RFC2765
RFC6145
RFC7915
~/
$ rfcbibtex -f rfc.txt
@misc{RFC2765,
        series =        {Request for Comments},
        number =        2765,
        howpublished =  {RFC 2765},
        publisher =     {RFC Editor},
        doi =           {10.17487/RFC2765},
        url =           {https://rfc-editor.org/rfc/rfc2765.txt},
        author =        {Erik Nordmark},
        title =         {{Stateless IP/ICMP Translation Algorithm (SIIT)}},
        pagetotal =     26,
        year =          2000,
        month =         feb,
        abstract =      {This document specifies a transition mechanism algorithm in addition to the mechanisms already specified. {[}STANDARDS-TRACK{]}},
}

@misc{RFC6145,
        series =        {Request for Comments},
        number =        6145,
        howpublished =  {RFC 6145},
        publisher =     {RFC Editor},
        doi =           {10.17487/RFC6145},
        url =           {https://rfc-editor.org/rfc/rfc6145.txt},
        author =        {Xing Li and Fred Baker and Congxiao Bao},
        title =         {{IP/ICMP Translation Algorithm}},
        pagetotal =     33,
        year =          2011,
        month =         apr,
        abstract =      {This document describes the Stateless IP/ICMP Translation Algorithm (SIIT), which translates between IPv4 and IPv6 packet headers (including ICMP headers). This document obsoletes RFC 2765. {[}STANDARDS-TRACK{]}},
}

@misc{RFC7915,
        series =        {Request for Comments},
        number =        7915,
        howpublished =  {RFC 7915},
        publisher =     {RFC Editor},
        doi =           {10.17487/RFC7915},
        url =           {https://rfc-editor.org/rfc/rfc7915.txt},
        author =        {Congxiao Bao and Xing Li and Fred Baker and Tore Anderson and Fernando Gont},
        title =         {{IP/ICMP Translation Algorithm}},
        pagetotal =     34,
        year =          2016,
        month =         jun,
        abstract =      {This document describes the Stateless IP/ICMP Translation Algorithm (SIIT), which translates between IPv4 and IPv6 packet headers (including ICMP headers). This document obsoletes RFC 6145.},
}

installation

Python 3.xが必要だそうです.

pip install rfcbibtex
# pip3 install rfcbibtex 

[CWT入門その3] クレームもコンパクトに表現された CBOR Web Token (RFC8392)

どーも、ritouです。

アドカレ

これは認証認可技術 Advent Calendar 2019 19日めの記事が空いてたので代わりにします。

概要

この投稿はCBOR Web Token(CWT)入門3部作の第3弾です。

これまでCBOR, COSEについて紹介しました。

今回紹介する CBOR Web Token(CWT) では、 CBOR によりエンコードされ、 COSE により暗号化/署名付きでやりとりされる標準的なクレームの表現が定義されています。

CBOR Web Token (CWT)

RFC化のタイミングとしては CBOR が2013年、 COSE が2017年、CWT は2018年です。
RFC や IETF Draft の仕様を見たことがある人は、目次やスクロールバーの長さを見るだけで「こいつ...短いな?」と気づくでしょう。

一言でいうと、「RFC7519 JSON Web Token(JWT)で定義されているクレームを CBOR オブジェクトに突っ込むために Claim Keyという整数をふったよ」ぐらいです。

それでは見ていきましょう。

Claims

有効な CWT に含まれる一連のクレームは、コンテキストに依存し、この仕様の対象外です。
特別な要件がない限り、実装によって理解されないクレームは無視されなければならない(MUST)

これはお決まりな文言という感じでしょう。

Registered Claims

ここで登録されているクレームのいずれも、使用や実装が必須にはなっていない。
便利で相互運用可能なクレームの集合としての出発点であり、利用するアプリケーションがどのようなクレームを利用すべきか、必須か任意かを定義すべき。

ということで、柔軟に使っていけという感じです。
登録済みのクレームについて、JWTとほぼ同じで JWT IDの部分が CWT IDになっています。

Name(CWT)Name(JWT)
ississ
subsub
audaud
expexp
nbfnbf
iatiat
cti(diff!)jti

それぞれのクレームについての説明は省略されていますが、振り返っておきます。

  • iss (Issuer) Claim : CWT の発行者. フォーマットは文字列
  • sub (Subject) Claim : CWT の主体、対象者. フォーマットは文字列
  • aud (Audience) Claim : CWT の受信者の識別子. フォーマットは文字列もしくは文字列を要素にもつ配列
  • exp (Expiration Time) Claim : CWT の有効期限. フォーマットは整数もしくは浮動小数点数
  • nbf (Not Before) Claim : この日時まで CWT を受け入れてはいけないという値. フォーマットは整数もしくは浮動小数点数
  • iat (Issued At) Claim : CWT の発行日時. フォーマットは整数もしくは浮動小数点数
  • cti (CWT ID) Claim : CWT を識別する値で、値のフォーマットはバイナリ列

自分が JWT を多用してきた経験からすると、単一もしくは複数パーティー間のやりとりではこれらのクレームのどれかを選択 + ちょっと独自のを追加ぐらいで済むパターンが多い気がします。

また、 JWT との違いとして、それぞれに 1 ~ 7 の整数が割り当てられています。

NameKeyValue Type
iss1text string
sub2text string
aud3text string (or text string array)
exp4integer or floating-point number
nbf5integer or floating-point number
iat6integer or floating-point number
cti7byte string

クレームとして CBOR Object にする際に、Name の文字列ではなく Key の整数を map の key に用いることでコンパクトな表現が実現可能となります。

OAuthの仕様でJWTのclaimが追加されたりしたこともあるので、今後追加されることもありえます。
独自でキーを考えて実装する際にはその辺りも想定しておきたいところではありますが、後から出てきた仕様で重複したらちょっと切ないですね。

サンプルとして記載されている CWT Claim Set を見てみましょう。

# hexed
a70175636f61703a2f2f61732e6578616d706c652e636f6d02656572696b77037818636f61703a2f2f6c696768742e6578616d706c652e636f6d041a5612aeb0051a5610d9f0061a5610d9f007420b71

# hexed を cbor.me で確認
A7                                      # map(7)
   01                                   # unsigned(1)
   75                                   # text(21)
      636F61703A2F2F61732E6578616D706C652E636F6D # "coap://as.example.com"
   02                                   # unsigned(2)
   65                                   # text(5)
      6572696B77                        # "erikw"
   03                                   # unsigned(3)
   78 18                                # text(24)
      636F61703A2F2F6C696768742E6578616D706C652E636F6D # "coap://light.example.com"
   04                                   # unsigned(4)
   1A 5612AEB0                          # unsigned(1444064944)
   05                                   # unsigned(5)
   1A 5610D9F0                          # unsigned(1443944944)
   06                                   # unsigned(6)
   1A 5610D9F0                          # unsigned(1443944944)
   07                                   # unsigned(7)
   42                                   # bytes(2)
      0B71                              # "\vq"

# デコード結果
{
  / iss / 1: "coap://as.example.com",
  / sub / 2: "erikw",
  / aud / 3: "coap://light.example.com",
  / exp / 4: 1444064944,
  / nbf / 5: 1443944944,
  / iat / 6: 1443944944,
  / cti / 7: h'0b71'
}

iss の key には 1 が振られているため、01(hexed)となっていますが、仮に "iss"という文字列だった場合、63697373(hexed)となるので、整数を振ることでコンパクトに表現できてると言えるでしょう。

CBOR Tags and Claim Values

CBOR では、日時をタグ付きのデータとして表現できます。

# Standard date/time string

## hexed
c074323031332d30332d32315432303a30343a30305a

## with cbor.me
C0                                      # tag(0)
   74                                   # text(20)
      323031332D30332D32315432303A30343A30305A # "2013-03-21T20:04:00Z"

## tagged data
0("2013-03-21T20:04:00Z")

# Epoch-based date/time

## hexed
c11a514b67b0

## with cbor.me
C1             # tag(1)
   1A 514B67B0 # unsigned(1363896240)

## tagged data
1(1363896240)

しかし、この仕様で定義されている exp, nbf, iatの値ではそれらのタグ付き表現を採用していません。

Tagging claim values would only take up extra space without adding information.

JWTでもUNIXタイムスタンプだし、日時が入っていることが自明なのでタグつけないでサイズ抑えようなという感じでしょう。

CWT CBOR Tag

このデータは CWT であることをアプリケーションが判断できるようにいくつかの方法が定義されています。
COSEの解説にも出てきたと思いますが、バイナリデータを送信するときに application/cwtというcontent typeを用いたり、この CBOR データは CWT だよ!というのを CWT CBOR Tag をつけることで表現できます。

このタグを用いる場合は、必ず COSE CBOR Tag がついたオブジェクトに対してつけられます。

例えば、 COSE_Mac0オブジェクトには COSE_Mac0 CBOR Tag がついていて、その前に CWT CBOR Tag がつきます。

/ CWT CBOR tag / 61( # 一番最初(外側)につくよ的なイメージ
  / COSE_Mac0 CBOR tag / 17(
    / COSE_Mac0 object /
  )
)

Creating and Validating CWTs

最後に生成/検証方法です。COSEの復習という感じですね。

Creating a CWT

まずは生成手順です。

  1. CWT クレームセットを作成
  2. CWT クレームセットを CBOR でエンコードしてバイナリ表現にする
  3. COSE ヘッダを作成
  4. COSE の種類(signed/MACed/encrypted) による処理を行い、オブジェクトを作成
  5. ネストされた signed/MACed/encrypted の処理が必要な場合は、メッセージをタグ付きの COSE_Sign/COSE_Sign1, COSE_Mac/COSE_Mac0, COSE_Encrypt/COSE_Encrypt0としてステップ3に戻る
  6. 必要ならば、それぞれの種類に対応した COSE CBOR Tag をつけ、必要ならば CWT CBOR Tag をつける

この仕様に関わるのは 2,6 の部分だけですね。

Validating a CWT

  1. CWT が有効な CBOR オブジェクトであることを検証
  2. オブジェクトが CWT CBOR タグから始まるとき、それを削除して続くいずれかの COSE CBOR タグを検証
  3. オブジェクトが COSE CBOR タグを持っていたとき、それを削除して CWT の種類(COSE_Sign, COSE_Sign1, COSE_Mac, COSE_Mac0, COSE_Encrypt, COSE_Encrypt0)を特定する。COSE CBOR タグを持っていないときはアプリケーションコンテキストから特定する。
  4. COSE Header のパラメータと値の構文と瀬マンティクスが理解されサポートされているもののみであることを確認する。理解できない場合は無視する。
  5. CWT の種類に応じた処理
  6. メッセージ自体が COSE CBOR タグで始まる場合は再度 Step 1 からやり直す
  7. メッセージが CWT クレームセットに従った CBOR Map であることを検証

さらっと書いてますが、実装しようとすると 1 の漠然とした書き方が気になりますね。
デコードしてエラー出ないか確認するだけの is_cbor(binary)みたいな関数なイメージでしょうか。

この仕様に関わるのは最後の 7 のところです。

まとめ

  • JWT みたいなのの CBOR/COSE版を CWT と呼ぶ
  • CWT のクレームで一般的に使えそうなやつを定義し、キーに整数をふった
  • CBOR Map のあたりを含めた生成/検証方法を整理した

というあたりでした。これでCWT入門は完結です。

CWT完全に理解した!

ではまた。

配列要素を削除するとインデックスが残ったり残らなかったりする

PHPの配列は、キーのインデックスなどが配列側でしっかり管理されています。

$a=[];$a[]=1;$a[10]=2;$a[]=3;var_dump($a);// [0=>1, 10=>2, 11=>3]

キーを空白にすると、自動的に次のインデックスを割り当ててくれます。
とても便利。

しかしこのインデックス、一度増えるとその後値を消しても戻りません。

$a=[0,1];unset($a[1]);$a[]=2;var_dump($a);// [0=>0, 2=>2]

せっかく配列の最後の値を消したのに、使用した情報は残っていて次のキーは2になっています。
MySQLのauto_increment値と同様、一度上限が上がると下がらないということです。
全ての値を消したとしても同様です。

$a=[0,1];unset($a[1]);unset($a[0]);$a[]=2;var_dump($a);// [2=>2]

ところでこいつを見てくれ。

$a=[0,1];unset($a[1]);unset($a[0]);$b=$a;$a[]=2;var_dump($a);// [0=>2] ←

$b=$aと配列をコピーしたらインデックスの記憶が消え、また0から始まるようになりました。
なんでだよ。

さらにこっちも見てくれ。

$a=[0,1];unset($a[1]);unset($a[0]);$b=$a;$a[]=2;$b[]=3;var_dump($a);// [0=>2]var_dump($b);// [2=>3] ←

消えたと思っていたインデックスは、実はコピー先の$bに移っていたようです。
なんでだよ。

ところでNormalize arrays' "auto-increment" value on copy on writeというRFCが提出されているのですが、これは配列のコピーの仕組みを変えようという内容です。
具体的には配列のコピーを、以下のコードと同じにします。

$array_copy=[];foreach($arrayas$key=>$value){$array_copy[$key]=>$value;}

このRFCが適用されたらどうなるかというと、

$a=[0,1];unset($a[1]);unset($a[0]);$b=[];foreach($aas$k=>$v){$b[$k]=$v;}$a[]=2;$b[]=3;var_dump($a);// [2=>2]var_dump($b);// [0=>3]

解決してなくない?

【PHP8.0】マイナススタートの配列インデックスが使えるようになる

PHP7.4
$arr=[];$arr[-10]=1;$arr[]=1;

どうなるかというと[-10=>1, 0=>1]です。

これはマニュアルにも明記されています。

1.png

しかしこの動作はPHP8.0で変更になります。
Arrays starting with a negative indexというRFCにおいて変更が決定しました。

Arrays starting with a negative index

Introduction

array_fillのドキュメントには、『start_index が負の場合は、 返される配列の最初のインデックスが start_index となり、それ以降のインデックスはゼロから始まります』とあります。

明示的に負のキーを使用し、その後キーを省略した場合は常にこのような動作になります。

Proposal

現在の動作は、最後の数値キーがnであった場合、次の暗黙キーはn>=0であればn+1n<0であれば0ということになります。

このRFCでは、nの符号に関係なく常にn+1とすることによって、この動作を一貫させることを目指しています。

配列のドキュメントにもわざわざ注釈として書かれているように、これは例外的な動作であり、学習コストとなります。

このプロポーザルはPHP8.0を対象としています。
この変更により問題が発生する可能性がある場合、移行を容易にするために非推奨の通知を出すことも提案します。

以下のコードは全て同じ結果になります。

$a=array_fill(-2,3,true);$b=[-2=>true,true,true];$c=["string"=>true,-2=>true,true,true];unset($c["string"]);$d[-2]=true;$d[]=true;$d[]=true;

現在は全て以下のようになります。

~PHP7.4
array(3){[-2]=>bool(true)[0]=>bool(true)[1]=>bool(true)}

このRFCにより、以下の動作に変更になります。

PHP8.0~
array(3){[-2]=>bool(true)[-1]=>bool(true)[0]=>bool(true)}

非推奨を出力する投票が受理された場合、移行フェーズ中は以下のE_DEPRECATEDを発生させます。

Deprecated: In the next major version of PHP the implicit keys of this array will start from -1 instead of 0 in ...

Backward Incompatible Changes

配列を負のインデックスから開始し、その後暗黙のキーを使い、そして明示的なキーで配列要素にアクセスした際に影響が発生します。

$a[-2]=true;// 現行:キーは-2 / RFC:キーは-2$a[]=true;// 現行:キーは0 / RFC:キーは-1$a[]=true;// 現行:キーは1 / RFC:キーは-0if($a[1]===true){echo'Accessing key 1 explicitly';}

PHP8.0以降、'Accessing key 1 explicitly'が出力されなくなります。

Proposed PHP Version(s)

PHP8.0。

Unaffected PHP Functionality

明示的なキー、文字列のキーには影響しません。
また、-1以上の数値インデックスを持つ配列も影響を受けません。
最初から暗黙のキーを使う配列のインデックスは0から始まります。

キーを使用しないforeachも影響を受けません。

投票

このRFCは賛成17反対2で可決されました。

E_DEPRECATEDを出す提案は賛成8反対14で却下されました。

すなわち、PHP8.0で前触れなく突然動作が変更になります。

感想

PHP4.2から長い時を経て、元の鞘に戻ることになりました。
さすがに当時のことは知らないので、どうして変更されたのかは全くわかりません。

しかし、この仕様に依存する実装をしている人なんていないでしょう。
すなわち実質的な影響はほぼゼロです。
そもそもネガティブスタートの配列って何に使うんだろうか?

ただ、MySQLのAUTO_INCREMENTマイナスは使えないですし、あえて変更する必要があるのかは少し疑問です。

あと配列をコピーしたら何かおきそうで少し楽しみですね。

Autosar Specification of TCP/IP Stack を読む

Specification of TCP/IP Stack

過去の2文書と比較して、最新文書を確認する。

https://www.autosar.org/fileadmin/user_upload/standards/classic/4-1/AUTOSAR_SWS_TcpIp.pdf

https://www.autosar.org/fileadmin/user_upload/standards/classic/4-3/AUTOSAR_SWS_TcpIp.pdf

https://www.autosar.org/fileadmin/user_upload/standards/classic/19-11/AUTOSAR_SWS_TcpIp.pdf

2 Acronyms and abbreviations

略号を定義している標準等を順次追記予定。

Abbreviation / AcronymDescription
ARPAddress Resolution Protocol
DADDuplicate Address Detection
DEMDiagnostic Event Manager
DETDefault Error Tracer
DHCPDynamic Host Configuration Protocol
DHCPv4Dynamic Host Configuration Protocol for Internet Protocol Version 4
ECUElectronic Control Unit
EthIfEthernet Interface
EthSMEthernet State Manager
HSMHardware Security Module
HTTPHyperText Transfer Protocol
IANAInternet Assigned Numbers Authority
ICMPInternet Control Message Protocol
ICMPv4Internet Control Message Protocol for Internet Protocol Version 4
IETFInternet Engineering Task Force
IPInternet Protocol
IPsecInternet Protocol Security
IPv4Internet Protocol version 4
IPv6Internet Protocol version 6
MTUMaximum Transmission Unit
NDPNeighbor Discovery Protocol
PKIPublic Key Infrastructure
PRFPseudo Random Function
RNGRandom Number Generator
RSARivest-Shamir-Adleman. A method using public and private key for data encryption and decryption.
SNIServer Name Identification
SoAdSocket Adaptor
TCPTransmission Control Protocol
TCP/IPA family of communication protocols used in computer networks TLS Transport Layer Security
TPTransport Protocol
UDPUser Datagram Protocol

CDD
EQDn
DTLS
STD
CSM
KEYM
COM

3 Related documentation

文書名、発行年、URLがないものは順次追記予定。

RFC7628
RFC7685

3.1 Input documents

[1] AUTOSAR Layered Software Architecture AUTOSAR_EXP_LayeredSoftwareArchitecture.pdf
[2] AUTOSAR Basis Software Mode Manager AUTOSAR_SWS_BSWModeManager.pdf
[3] AUTOSAR Socket Adaptor AUTOSAR_SWS_SocketAdaptor.pdf
[4] AUTOSAR SRS BSW General AUTOSAR_SRS_BSWGeneral.pdf
[5] AUTOSAR SRS Ethernet AUTOSAR_SRS_Ethernet.pdf
[6] AUTOSAR General Specification for Basic Software Modules AUTOSAR_SWS_BSWGeneral.pdf
[7] Specification of ECU Configuration AUTOSAR_TPS_ECUConfiguration.pdf
[8] List of Basic Software Modules AUTOSAR_TR_BSWModuleList.pdf
[9] Specification of Crypto Service Manager AUTOSAR_SWS_CryptoServiceManager.pdf
[10] Specification of Key Manager AUTOSAR_SWS_KeyManager.pdf
[11] AUTOSAR RS IPsecProtocol AUTOSAR_RS_IPsecProtocol.pdf

3.2 Related standards and norms

[12] IETF RFC 3927 Dynamic Configuration of IPv4 Link-Local Addresses
, May 2005, http://tools.ietf.org/html/rfc3927
[13] IETF RFC 1122 Requirements for Internet Hosts -- Communication Layers, October 1989, http://tools.ietf.org/html/rfc1122
[14] IETF RFC 826 An Ethernet Address Resolution Protocol or Converting Network Protocol Addresses, November 1982, http://tools.ietf.org/html/rfc826

[15] IETF RFC 894 A Standard for the Transmission of IP Datagrams over Ethernet Networks, April 1984, http://tools.ietf.org/html/rfc894
[16] IETF RFC 791 INTERNET PROTOCOL, September 1981, http://tools.ietf.org/html/rfc791
[17] IETF RFC 815 IP DATAGRAM REASSEMBLY ALGORITHMS, July, 1982, http://tools.ietf.org/html/rfc815
[18] IETF RFC 4632 Classless Inter-domain Routing (CIDR): The Internet Address Assignment and Aggregation Plan, August 2006, http://tools.ietf.org/html/rfc4632
[19] IETF RFC 1112 Host Extensions for IP Multicasting, August 1989, http://tools.ietf.org/html/rfc1112
[20] IETF RFC 792 INTERNET CONTROL MESSAGE PROTOCOL, September 1981, http://tools.ietf.org/html/rfc792
[21] IETF RFC 1191 Path MTU Discovery, November 1990, http://tools.ietf.org/html/rfc1191
[22] IETF RFC 2131 Dynamic Host Configuration Protocol, March 1997, http://tools.ietf.org/html/rfc2131
[23] IETF RFC 768 User Datagram Protocol, 28 August 1980, http://tools.ietf.org/html/rfc768
[24] IETF RFC 793 TRANSMISSION CONTROL PROTOCOL, September 1981, http://tools.ietf.org/html/rfc793
[25] IETF RFC 5681 TCP Congestion Control, September 2009, http://tools.ietf.org/html/rfc5681
[26] IETF RFC 8200 Internet Protocol, Version 6 (IPv6) Specification, July 2017, http://tools.ietf.org/html/rfc8200
[27] IETF RFC 4291 IP Version 6 Addressing Architecture, February 2006, http://tools.ietf.org/html/rfc4291
[28] IETF RFC 2464 Transmission of IPv6 Packets over Ethernet Networks, December 1998, http://tools.ietf.org/html/rfc2464
[29] IETF RFC 6724 Default Address Selection for Internet Protocol Version 6 (IPv6), September 2012, http://tools.ietf.org/html/rfc6724
[30] IETF RFC 5722 Handling of Overlapping IPv6 Fragments, December 2009, http://tools.ietf.org/html/rfc5722
[31] IETF RFC 5095 Deprecation of Type 0 Routing Headers in IPv6, December 2007, http://tools.ietf.org/html/rfc5095
[32] IETF RFC 4862 IPv6 Stateless Address Autoconfiguration, September 2007, http://tools.ietf.org/html/rfc4862
[33] IETF RFC 1981 Path MTU Discovery for IP version 6, August 1996, http://tools.ietf.org/html/rfc1981
[34] IETF RFC 4429 Optimistic Duplicate Address Detection (DAD) for IPv6, April 2006, http://tools.ietf.org/html/rfc4429
[35] IETF RFC 4443 Internet Control Message Protocol (ICMPv6) for the Internet Protocol Version 6 (IPv6) Specification, March 2006, http://tools.ietf.org/html/rfc4443
[36] IETF RFC 4861 Neighbor Discovery for IP version 6 (IPv6), September 2007, http://tools.ietf.org/html/rfc4861
[37] IETF RFC 3315 Dynamic Host Configuration Protocol for IPv6 (DHCPv6), July 2003, http://tools.ietf.org/html/rfc3315
[38] IETF RFC 4702 The Dynamic Host Configuration Protocol (DHCP) Client Fully Qualified Domain Name (FQDN) Option, October 2006, http://tools.ietf.org/html/rfc4702
[39] IETF RFC 4704 The Dynamic Host Configuration Protocol for IPv6 (DHCPv6) Client Fully Qualified Domain Name (FQDN) Option, October 2006, http://tools.ietf.org/html/rfc4704
[40] IETF RFC 6582 The NewReno Modification to TCP's Fast Recovery Algorithm, April 2012, http://tools.ietf.org/html/rfc6582
[41] IETF RFC 2132 DHCP Options and BOOTP Vendor Extensions, March 1997, http://tools.ietf.org/html/rfc2132
[42] IETF RFC 5942 IPv6 Subnet Model: The Relationship between Links and Subnet Prefixes, July 2010, https://tools.ietf.org/html/rfc5942
[43] IETF RFC 6437 IPv6 Flow Label Specification, November 2011, https://tools.ietf.org/html/rfc6437
[44] IETF RFC 2474 Definition of the Differentiated Services Field (DS Field) in the IPv4 and IPv6 Headers, December 1998, https://tools.ietf.org/html/rfc2474
[45] IETF RFC 5246 The Transport Layer Security (TLS) Protocol Version 1.2, August 2008, https://tools.ietf.org/html/rfc5246
[46] IETF RFC 4492 Elliptic Curve Cryptography (ECC) Cipher Suites for Transport Layer Security (TLS), May 2006, https://tools.ietf.org/html/rfc4492
[47] IETF RFC 7525 Recommendations for Secure Use of Transport Layer Security (TLS) and Datagram Transport Layer Security (DTLS), May 2015, https://tools.ietf.org/html/rfc7525
[48] IETF RFC 4279 Pre-Shared Key Ciphersuites for Transport Layer Security (TLS), December 2005, https://tools.ietf.org/html/rfc4279
[49] IETF RFC 7366 Encrypt-then-MAC for Transport Layer Security (TLS) and Datagram Transport Layer Security (DTLS), September 2014, https://tools.ietf.org/html/rfc7366
[50] IETF RFC 8446 The Transport Layer Security (TLS) Protocol Version 1.3, August 2018
https://tools.ietf.org/html/rfc8446
[51] IETF RFC 8449 Record Size Limit Extension for TLS, August 2018, https://tools.ietf.org/html/rfc8449
[52] IANA DHCP Options https://www.iana.org/assignments/bootp-dhcp-parameters/bootp-dhcp-parameters.xhtml#options
[53] IANA DHCPv6 Options https://www.iana.org/assignments/dhcpv6-parameters/dhcpv6-parameters.xhtml#dhcpv6-parameters-2
[54] RfC 4301 Security Architecture for the Internet Protocol, December 2005, https://tools.ietf.org/html/rfc4301
[55] RfC 4302 IP Authentication Header, December 2005, https://tools.ietf.org/html/rfc4302
[56] RfC 4303 IP Encapsulating Security Payload (ESP), December 2005, https://tools.ietf.org/html/rfc4303
[57] RfC 7296 Internet Key Exchange Protocol Version 2 (IKEv2), October 2014, https://tools.ietf.org/html/rfc7296
[58] RfC 4304 Extended Sequence Number (ESN) Addendum to IPsec Domain of Interpretation (DOI) for Internet Security Association, December 2005, https://tools.ietf.org/html/rfc4304
[59] RfC 8221 Cryptographic Algorithm Implementation Requirements and Usage Guidance for Encapsulating Security Payload (ESP) and Authentication Header (AH), October 2017, https://tools.ietf.org/html/rfc8221
[60] RfC 4478 Repeated Authentication in Internet Key Exchange (IKEv2) Protocol, April 2006, https://tools.ietf.org/html/rfc4478
[61] RfC 3706 A Traffic-Based Method of Detecting Dead Internet Key Exchange (IKE) Peers, Cisco Systems, February 2004, https://tools.ietf.org/html/rfc3706
[62] RfC 7427 Signature Authentication in the Internet Key Exchange Version 2 (IKEv2), January 2015, https://tools.ietf.org/html/rfc7427
[63] RfC 4543 The Use of Galois Message Authentication Code (GMAC) in IPsec ESP and AH, May 2006, https://tools.ietf.org/html/rfc4543
[64] RfC 4494 The AES-CMAC-96 Algorithm and Its Use with IPsec, June 2006, https://tools.ietf.org/html/rfc4494
[65] RfC 4106 The Use of Galois/Counter Mode (GCM) in IPsec Encapsulating Security Payload (ESP), June 2005, https://tools.ietf.org/html/rfc4106
[66] RfC 4309 Using Advanced Encryption Standard (AES) CCM Mode with IPsec Encapsulating Security Payload (ESP), December 2005, https://tools.ietf.org/html/rfc4309
[67] RfC 6379 Suite B Cryptographic Suites for IPsec, October 2011, https://tools.ietf.org/html/rfc6379
[68] RfC 8247 Algorithm Implementation Requirements and Usage Guidance for the Internet Key Exchange Protocol Version 2 (IKEv2), September 2017, https://tools.ietf.org/html/rfc8247
[69] RfC 7383 Internet Key Exchange Protocol Version 2 (IKEv2) Message Fragmentation, November 2014, https://tools.ietf.org/html/rfc7383
[70] ISO13400-2 Road vehicles - Diagnostic communication over Internet Protocol (DoIP) — Part 2: Transport protocol and network layer services, https://www.iso.org/standard/53766.html

参考資料(reference)

なぜ参考文献に標題、発行年、URLを入れるか
https://qiita.com/kaizen_nagoya/items/f312746485b86a2e4292

Autosar文書、参考文献、略号一覧(作成中37/237):英語(40)
https://qiita.com/kaizen_nagoya/items/2325b0156bc7fcf5a96d

隧道規約(tunneling protocol)

専門は通信規約(communication protocol)です。

遅延測定、経路制御、無線通信が主要な領域です。

具体的には、PHS, GPS, SoftEtherなどが対象領域です。

SoftEtherを知る
https://qiita.com/kaizen_nagoya/items/7a4062f845ebb2539e25

RFCでは、NTP, Mobile IP, Tunnelingです。

遅延測定には時刻同期が鍵です。
Mobile IPは移動対応の Tunnelingかもしれません。

https://ja.wikipedia.org/wiki/トンネリング

記事に参照がなく、内容としても乏しい。

https://ja.wikipedia.org/wiki/Layer_2_Tunneling_Protocol

隧道規約

網祭隧道規約(IP tunneling)

トンネル掘削機
https://tdtds.jp/tunnel/

トンネリング (tunneling) 佐々木 真(ササキ マコト)at「分かりそう」で「分からない」でも「分かった」気になれるIT用語辞典
https://wa3.i-3-i.info/word12036.html

通信で使う“トンネル”ってどんなもの?
https://tech.nikkeibp.co.jp/it/article/COLUMN/20101001/352543/

オーバーレイ (トンネル) プロトコル
https://docs.openstack.org/ocata/ja/networking-guide/intro-overlay-protocols.html

VPNを支えるトンネル技術
http://ponsuke-tarou.hatenablog.com/entry/2019/08/23/170733

第 􏰁11部 トンネリング技術
http://www.wide.ad.jp/About/report/pdf1992/part11.pdf

TCP-Tunneling at AnyDesk
https://support.anydesk.com/TCP-Tunneling

 VPN におけるトンネリングと暗号化
https://www.infraexpert.com/study/ipsec2.html

トンネリングプロトコルについて
https://www.infraexpert.com/info/5.4adsl.htm

IP トンネルの概要 
https://docs.oracle.com/cd/E26924_01/html/E25872/gepbe.html

DNSトンネリング: 攻撃者はDNSをどう悪用するのか
https://www.paloaltonetworks.jp/company/in-the-news/2019/dns-tunneling-how-dns-can-be-abused-by-malicious-actors

個別機器

VPN接続方式
https://network.yamaha.com/knowledge/vpn/protocol

M2Mデータマネジメント > Cogent DataHub V8 > トンネリング機能
https://www.co-nss.co.jp/products/management/tunnel.html

13.11.4 トンネル機能使用時の注意事項 ALAXALA Networks Corporation.
https://www.alaxala.com/jp/techinfo/archive/manual/AX7700R/HTML/10_10_/APGUIDE/0313.HTM

Windows Server 2016 の GRE トンネリング
https://docs.microsoft.com/ja-jp/windows-server/remote/remote-access/ras-gateway/gre-tunneling-windows-server

トンネリング・トンネリング接続 とは
https://www.liveon.ne.jp/glossary/wk/tunneling.html

RFC

RFC1853

IP in IP Tunneling
https://tools.ietf.org/html/rfc1853

References

[IDM91a] Ioannidis, J., Duchamp, D., Maguire, G., "IP-based
protocols for mobile internetworking", Proceedings of
SIGCOMM '91, ACM, September 1991.

[RFC-791]
Postel, J., "Internet Protocol", STD 5, RFC 791,
USC/Information Sciences Institute, September 1981.
https://tools.ietf.org/html/rfc791

[RFC-792]
Postel, J., "Internet Control Message Protocol", STD 5 RFC 792, USC/Information Sciences Institute, September 1981.
https://tools.ietf.org/html/rfc792

[RFC-1191]
Mogul, J., and S. Deering, "Path MTU Discovery", RFC 1191,
DECWRL, Stanford University, November 1990.

[RFC-1241]
Mills, D., and R. Woodburn, "A Scheme for an Internet
Encapsulation Protocol: Version 1", UDEL, July 1991.
https://tools.ietf.org/html/rfc1241

[RFC-1435]
Knowles, S., "IESG Advice from Experience with Path MTU
Discovery", RFC 1435, FTP Software, March 1993.
https://tools.ietf.org/html/rfc1435

[RFC-1700]
Reynolds, J., and J. Postel, "Assigned Numbers", STD 2, RFC
1700, USC/Information Sciences Institute, October 1994.
https://tools.ietf.org/html/rfc1700

[RFC-1701]
Hanks, S., Li, T., Farinacci, D., and P. Traina, "Generic
Routing Encapsulation (GRE)", RFC 1701, October 1994.
https://tools.ietf.org/html/rfc1701

[swIPe] Ioannidis, J., and Blaze, M., "The Architecture and
Implementation of Network-Layer Security Under Unix", Fourth
Usenix Security Symposium Proceedings, October 1993.

RFC2341

Cisco Layer Two Forwarding (Protocol) "L2F"
https://tools.ietf.org/html/rfc2341

7.0 References

[1] Romkey, J., "A Nonstandard for Transmission of IP Datagrams over
Serial Lines: SLIP", RFC 1055, June 1988.

[2] Simpson, W., "The Point-to-Point Protocol (PPP)", STD 51,
RFC 1661, July 1994.
https://tools.ietf.org/html/rfc1661

[3] Simpson, W., "PPP in HDLC-like Framing", STD 51,, RFC 1662,
July 1994.
https://tools.ietf.org/html/rfc1662

[4] Reynolds, J., and J. Postel, "Assigned Numbers", STD 2, RFC 1700,
October 1994.
https://tools.ietf.org/html/rfc1700

[5] Hanks, S., Li, T., Farinacci, D., and P. Traina, "Generic Routing
Encapsulation (GRE)", RFC 1701, October 1994.
https://tools.ietf.org/html/rfc1701

RFC 2637

Point-to-Point Tunneling Protocol (PPTP)
https://tools.ietf.org/html/rfc2637

  1. References

[1] Hanks, S., Li, T., Farinacci, D. and P. Traina, "Generic Routing
Encapsulation (GRE)", RFC 1701, October 1994.
https://tools.ietf.org/html/rfc1701

[2] Hanks, S., Li, T., Farinacci, D. and P. Traina, "Generic Routing
Encapsulation (GRE) over IPv4 Networks", RFC 1702, October 1994.
https://tools.ietf.org/html/rfc1702

[3] Lloyd, B. and W. Simpson, "PPP Authentication Protocols", RFC
1334, October 1992.
https://tools.ietf.org/html/rfc1334

[4] Postel, J., "Transmission Control Protocol", STD 7, RFC 793,
September 1981.

[5] Postel, J., "User Data Protocol", STD 6, RFC 768, August 1980.

[6] Reynolds, J. and J. Postel, "Assigned Numbers", STD 2, RFC 1700,
October 1994. See also: http://www.iana.org/numbers.html

[7] Simpson, W., editor, "The Point-to-Point Protocol (PPP)", STD
51, RFC 1661, July 1994.

[8] Ethertype for PPP, Reserved with Xerox Corporation.

[9] Simpson, W., "PPP Challenge Handshake Authentication Protocol
(CHAP)", RFC 1994, August 1996.

[10] Blunk, L. and J Vollbrecht, "PPP Extensible Authentication
Protocol (EAP)", RFC 2284, March 1998.

[11] Stevens, R., "TCP/IP Illustrated, Volume 1", p. 300, Addison-
Wesley, 1994.

[12] Bradner, S., "Key words for use in RFCs to Indicate Requirement
Levels", BCP 14, RFC 2119, March 1997.

RFC2661

Layer Two Tunneling Protocol "L2TP"
https://tools.ietf.org/html/rfc2661

11.0 References

[DSS1] ITU-T Recommendation, "Digital subscriber Signaling System
No. 1 (DSS 1) - ISDN user-network interface layer 3
specification for basic call control", Rec. Q.931(I.451),
May 1998

[KPS] Kaufman, C., Perlman, R., and Speciner, M., "Network
Security: Private Communications in a Public World",
Prentice Hall, March 1995, ISBN 0-13-061466-1

[RFC791] Postel, J., "Internet Protocol", STD 5, RFC 791, September
1981.

[RFC1034] Mockapetris, P., "Domain Names - Concepts and Facilities",
STD 13, RFC 1034, November 1987.

[RFC1144] Jacobson, V., "Compressing TCP/IP Headers for Low-Speed
Serial Links", RFC 1144, February 1990.

[RFC1661] Simpson, W., "The Point-to-Point Protocol (PPP)", STD 51,
RFC 1661, July 1994.

[RFC1662] Simpson, W., "PPP in HDLC-like Framing", STD 51, RFC 1662,
July 1994.

[RFC1663] Rand, D., "PPP Reliable Transmission", RFC 1663, July 1994.

[RFC1700] Reynolds, J. and J. Postel, "Assigned Numbers", STD 2, RFC
1700, October 1994. See also:
http://www.iana.org/numbers.html
[RFC1990] Sklower, K., Lloyd, B., McGregor, G., Carr, D. and T.
Coradetti, "The PPP Multilink Protocol (MP)", RFC 1990,
August 1996.

[RFC1994] Simpson, W., "PPP Challenge Handshake Authentication
Protocol (CHAP)", RFC 1994, August 1996.

[RFC1918] Rekhter, Y., Moskowitz, B., Karrenberg, D., de Groot, G.
and E. Lear, "Address Allocation for Private Internets",
BCP 5, RFC 1918, February 1996.
[RFC2119] Bradner, S., "Key words for use in RFCs to Indicate
Requirement Levels", BCP 14, RFC 2119, March 1997.

[RFC2138] Rigney, C., Rubens, A., Simpson, W. and S. Willens, "Remote
Authentication Dial In User Service (RADIUS)", RFC 2138,
April 1997.

[RFC2277] Alvestrand, H., "IETF Policy on Character Sets and
Languages", BCP 18, RFC 2277, January 1998.

[RFC2341] Valencia, A., Littlewood, M. and T. Kolar, "Cisco Layer Two
Forwarding (Protocol) L2F", RFC 2341, May 1998.

[RFC2401] Kent, S. and R. Atkinson, "Security Architecture for the
Internet Protocol", RFC 2401, November 1998.

[RFC2434] Narten, T. and H. Alvestrand, "Guidelines for Writing an
IANA Considerations Section in RFCs", BCP 26, RFC 2434,
October 1998.

[RFC2637] Hamzeh, K., Pall, G., Verthein, W., Taarud, J., Little, W.
and G. Zorn, "Point-to-Point Tunneling Protocol (PPTP)",
RFC 2637, July 1999.

[STEVENS] Stevens, W. Richard, "TCP/IP Illustrated, Volume I The
Protocols", Addison-Wesley Publishing Company, Inc., March
1996, ISBN 0-201-63346-9

RFC 2867

RADIUS Accounting Modifications for Tunnel Protocol Support トンネルプロトコルサポートのためのラディウス課金変更
http://www5d.biglobe.ne.jp/stssk/rfc/rfc2867j.html
https://tools.ietf.org/html/rfc2867

  1. References

[1] Rigney, C., "RADIUS Accounting", RFC 2866, June 2000.

[2] Bradner, S., "Key words for use in RFCs to Indicate Requirement
Levels", BCP 14, RFC 2119, March 1997.

[3] Zorn, G., Leifer, D., Rubens, A., Shriver, J., Holdrege, M. and
I. Goyret, "RADIUS Attributes for Tunnel Protocol Support", RFC
2868, June 2000.

[4] Townsley, W., Valencia, A., Rubens, A., Pall, G., Zorn, G. and
B. Palter, "Layer Two Tunneling Protocol "L2TP"", RFC 2661,
August 1999.

[5] Hamzeh, K., Pall, G., Verthein, W., Taarud, J., Little, W. and
G. Zorn, "Point-to-Point Tunneling Protocol (PPTP)", RFC 2637,
July 1999.

RFC 2868

RADIUS Attributes for Tunnel Protocol Support
https://tools.ietf.org/html/rfc2868

  1. References

[1] Hamzeh, K., Pall, G., Verthein, W., Taarud, J., Little, W. and
G. Zorn, "Point-to-Point Tunneling Protocol (PPTP)", RFC 2637,
July 1999.

[2] Valencia, A., Littlewood, M. and T. Kolar, T., "Cisco Layer Two
Forwarding (Protocol) 'L2F'", RFC 2341, May 1998.

[3] Townsley, W., Valencia, A., Rubens, A., Pall, G., Zorn, G. and
B. Palter, "Layer Two Tunnelling Protocol (L2TP)", RFC 2661,
August 1999.

[4] Hamzeh, K., "Ascend Tunnel Management Protocol - ATMP", RFC
2107, February 1997.

[5] Kent, S. and R. Atkinson, "Security Architecture for the
Internet Protocol", RFC 2401, November 1998.

[6] Perkins, C., "IP Encapsulation within IP", RFC 2003, October
1996.

[7] Perkins, C., "Minimal Encapsulation within IP", RFC 2004,
October 1996.

[8] Atkinson, R., "IP Encapsulating Security Payload (ESP)", RFC
1827, August 1995.

[9] Hanks, S., Li, T., Farinacci, D. and P. Traina, "Generic Routing
Encapsulation (GRE)", RFC 1701, October 1994.

[10] Simpson, W., "IP in IP Tunneling", RFC 1853, October 1995.

[11] Zorn, G. and D. Mitton, "RADIUS Accounting Modifications for
Tunnel Protocol Support", RFC 2867, June 2000.

[12] Rigney, C., Willens, S., Rubens, A. and W. Simpson, "Remote
Authentication Dial in User Service (RADIUS)", RFC 2865, June
2000.

[13] Bradner, S., "Key words for use in RFCs to Indicate Requirement
Levels", BCP 14, RFC 2119, March 1997.

[14] Reynolds, J. and J. Postel, "Assigned Numbers", STD 2, RFC 1700,
October 1994.

[15] Rigney, C., Willats, W. and P. Calhoun, "RADIUS Extensions", RFC
2869, June 2000.

[16] Narten, T. and H. Alvestrand, "Guidelines for writing an IANA
Considerations Section in RFCs", BCP 26, RFC 2434, October 1998.

[17] Hinden, R. and S. Deering, "IP Version 6 Addressing
Architecture", RFC 2373, July 1998.

RFC 3193

  Securing L2TP using IPsec

https://www.rfc-editor.org/rfc/rfc3193.txt

  1. References

[1] Townsley, W., Valencia, A., Rubens, A., Pall, G., Zorn, G., and
B. Palter, "Layer Two Tunneling Protocol L2TP", RFC 2661,
August 1999.

[2] Bradner, S., "Key words for use in RFCs to Indicate Requirement
Levels", BCP 14, RFC 2119, March 1997.

[3] Kent, S. and R. Atkinson, "IP Authentication Header", RFC 2402,
November 1998.

[4] Kent, S. and R. Atkinson, "IP Encapsulating Security Payload
(ESP)", RFC 2406, November 1998.

[5] Piper, D., "The Internet IP Security Domain of Interpretation
of ISAKMP", RFC 2407, November 1998.

[6] Atkinson, R. and S. Kent, "Security Architecture for the
Internet Protocol", RFC 2401, November 1998.

[7] Harkins, D. and D. Carrel, "The Internet Key Exchange (IKE)",
RFC 2409, November 1998.

[8] Simpson, W., "The Point-to-Point Protocol (PPP)", STD 51, RFC
1661, July 1994.

[9] Rand, D., "The PPP Compression Control Protocol (CCP)", RFC
1962, June 1996.

[10] Meyer, G., "The PPP Encryption Control Protocol (ECP)", RFC
1968, June 1996.

[11] Sklower, K. and G. Meyer, "The PPP DES Encryption Protocol
(DESE)", RFC 1969, June 1996.

[12] Sklower, K. and G. Meyer, "The PPP DES Encryption Protocol,
Version 2 (DESE-bis)", RFC 2419, September 1998.

[13] Hummert, K., "The PPP Triple-DES Encryption Protocol (3DESE)",
RFC 2420, September 1998.

[14] Dierks, T. and C. Allen, "The TLS Protocol Version 1.0", RFC
2246, November 1998.

[15] Simpson, W., "PPP Challenge Handshake Authentication Protocol
(CHAP)," RFC 1994, August 1996.

[16] Blunk, L. and J. Vollbrecht, "PPP Extensible Authentication
Protocol (EAP)," RFC 2284, March 1998.

[17] Hinden, R. and S. Deering, "IP Version 6 Addressing
Architecture", RFC 2373, July 1998.

RFC 3308

Layer Two Tunneling Protocol (L2TP) Differentiated Services Extension
https://tools.ietf.org/html/rfc3308

  1. References

[RFC 1661] Simpson, W., "The Point-to-Point Protocol (PPP)", STD 51,
RFC 1661, July 1994.

[RFC 2119] Bradner, S., "Key words for use in RFCs to Indicate
Requirement Levels", BCP 14, RFC 2119, March 1997.

[RFC 2474] Nichols, K., Blake, S., Baker, F. and D. Black "Definition
of the Differentiated Services Field (DS Field) in the
IPv4 and IPv6 Headers", RFC 2474, December 1998.

[RFC 2475] Blake, S., Black, D., Carlson, Z., Davies, E., Wang, Z.
and W. Weiss, "An Architecture for Differentiated
Services", RFC 2475, December 1998.

[RFC 2661] Townsley, W., Valencia, A., Rubens, A., Pall, G., Zorn, G.
and B. Palter, "Layer 2 Tunnel Protocol (L2TP)", RFC 2661,
August 1999.

[RFC 2983] Black, D., "Differentiated Services and Tunnels", RFC
2983, October 2000.

RFC3378

EtherIP: Tunneling Ethernet Frames in IP Datagrams
https://www.rfc-editor.org/rfc/rfc3378.txt

  1. References

[CSMA/CD] Institute of Electrical and Electronics Engineers:
"Carrier Sense Multiple Access with Collision Detection
(CSMA/CD) Access Method and Physical Layer Specifications",
ANSI/IEEE Std 802.3-1985, 1985.

[DIX] Digital Equipment Corporation, Intel Corporation, and Xerox
Corporation: "The Ethernet -- A Local Area Network: Data
Link Layer and Physical Layer (Version 2.0)", November
1982.

[RFC791] Postel, J., "Internet Protocol", STD 5, RFC 791, September
1981.

[RFC2119] Bradner, S., "Key Words for Use in RFCs to Indicate
Requirement Levels", BCP 14, RFC 2119, March 1997.

[RFC2338] Knight, S., Weaver, D., Whipple, D., Hinden, R., Mitzel,
D., Hunt, P., Higginson, P., Shand, M. and A. Lindem,
"Virtual Router Redundancy Protocol", RFC 2338, April 1998.

[RFC2401] Kent, S. and R. Atkinson, "Security Architecture for the
Internet Protocol", RFC 2401, November 1998.

[SDE] Institute of Electrical and Electronics Engineers:
"Interoperable LAN/MAN Security (SILS) Secure Data Exchange
(SDE) (Clause 2)", IEEE Std 802.10b-1992, 1992.

[XNS] Xerox Corporation: "Internet Transport Protocols", XSIS
028112, December 1981.

[VLAN] Institute of Electrical and Electronics Engineers: "IEEE
Standard for Local and Metropolitan Area Networks: Virtual
Bridge Local Area Networks", ANSI/IEEE Std 802.1Q-1998,
1998.

RFC 3391

Layer Two Tunneling Protocol - Version 3 (L2TPv3)
https://tools.ietf.org/html/rfc3931

  1. References

11.1. Normative References

[RFC2119] Bradner, S., "Key words for use in RFCs to Indicate
Requirement Levels", BCP 14, RFC 2119, March 1997.

[RFC2277] Alvestrand, H., "IETF Policy on Character Sets and
Languages", BCP 18, RFC 2277, January 1998.

[RFC2434] Narten, T. and H. Alvestrand, "Guidelines for Writing an
IANA Considerations section in RFCs", BCP 26, RFC 2434,
October 1998.

[RFC2473] Conta, A. and S. Deering, "Generic Packet Tunneling in IPv6
Specification", RFC 2473, December 1998.

[RFC2661] Townsley, W., Valencia, A., Rubens, A., Pall, G., Zorn, G.,
and Palter, B., "Layer Two Tunneling Layer Two Tunneling
Protocol (L2TP)", RFC 2661, August 1999.

[RFC2865] Rigney, C., Willens, S., Rubens, A., and W. Simpson,
"Remote Authentication Dial In User Service (RADIUS)", RFC
2865, June 2000.

[RFC3066] Alvestrand, H., "Tags for the Identification of Languages",
BCP 47, RFC 3066, January 2001.

[RFC3193] Patel, B., Aboba, B., Dixon, W., Zorn, G., and Booth, S.,
"Securing L2TP using IPsec", RFC 3193, November 2001.

[RFC3438] Townsley, W., "Layer Two Tunneling Protocol (L2TP) Internet
Assigned Numbers Authority (IANA) Considerations Update",
BCP 68, RFC 3438, December 2002.

[RFC3629] Yergeau, F., "UTF-8, a transformation format of ISO 10646",
STD 63, RFC 3629, November 2003.

11.2. Informative References

[RFC1034] Mockapetris, P., "Domain Names - Concepts and Facilities",
STD 13, RFC 1034, November 1987.

[RFC1191] Mogul, J. and S. Deering, "Path MTU Discovery", RFC 1191,
November 1990.

[RFC1321] Rivest, R., "The MD5 Message-Digest Algorithm", RFC 1321,
April 1992.

[RFC1661] Simpson, W., Ed., "The Point-to-Point Protocol (PPP)", STD
51, RFC 1661, July 1994.

[RFC1700] Reynolds, J. and Postel, J., "Assigned Numbers", STD 2, RFC
1700, October 1994.

[RFC1750] Eastlake, D., Crocker, S., and Schiller, J., "Randomness
Recommendations for Security", RFC 1750, December 1994.

[RFC1958] Carpenter, B., Ed., "Architectural Principles of the
Internet", RFC 1958, June 1996.

[RFC1981] McCann, J., Deering, S., and Mogul, J., "Path MTU Discovery
for IP version 6", RFC 1981, August 1996.

[RFC2072] Berkowitz, H., "Router Renumbering Guide", RFC 2072,
January 1997.

[RFC2104] Krawczyk, H., Bellare, M., and Canetti, R., "HMAC: Keyed-
Hashing for Message Authentication", RFC 2104, February
1997.

[RFC2341] Valencia, A., Littlewood, M., and Kolar, T., "Cisco Layer
Two Forwarding (Protocol) L2F", RFC 2341, May 1998.

[RFC2401] Kent, S. and Atkinson, R., "Security Architecture for the
Internet Protocol", RFC 2401, November 1998.

[RFC2581] Allman, M., Paxson, V., and Stevens, W., "TCP Congestion
Control", RFC 2581, April 1999.

[RFC2637] Hamzeh, K., Pall, G., Verthein, W., Taarud, J., Little, W.,
and Zorn, G., "Point-to-Point Tunneling Protocol (PPTP)",
RFC 2637, July 1999.

[RFC2732] Hinden, R., Carpenter, B., and Masinter, L., "Format for
Literal IPv6 Addresses in URL's", RFC 2732, December 1999.

[RFC2809] Aboba, B. and Zorn, G., "Implementation of L2TP Compulsory
Tunneling via RADIUS", RFC 2809, April 2000.

[RFC3070] Rawat, V., Tio, R., Nanji, S., and Verma, R., "Layer Two
Tunneling Protocol (L2TP) over Frame Relay", RFC 3070,
February 2001.

[RFC3355] Singh, A., Turner, R., Tio, R., and Nanji, S., "Layer Two
Tunnelling Protocol (L2TP) Over ATM Adaptation Layer 5
(AAL5)", RFC 3355, August 2002.

[KPS] Kaufman, C., Perlman, R., and Speciner, M., "Network
Security: Private Communications in a Public World",
Prentice Hall, March 1995, ISBN 0-13-061466-1.

[STEVENS] Stevens, W. Richard, "TCP/IP Illustrated, Volume I: The
Protocols", Addison-Wesley Publishing Company, Inc., March
1996, ISBN 0-201-63346-9.

RFC3519

Mobile IP Traversal of Network Address Translation (NAT) Devices
https://www.rfc-editor.org/rfc/rfc3519.txt

  1. Normative References

[1] Postel, J., "User Datagram Protocol", STD 6, RFC 768, August
1980.

[2] Postel, J., "Internet Protocol", STD 5, RFC 791, September 1981.

[3] Hanks, S., Li, T., Farinacci, D. and P. Traina, "Generic Routing
Encapsulation (GRE)", RFC 1701, October 1994.

[4] Perkins, C., "IP Encapsulation within IP", RFC 2003, October
1996.

[5] Perkins, C., "Minimal Encapsulation within IP", RFC 2004,
October 1996.

[6] Bradner, S., "Key words for use in RFCs to Indicate Requirement
Levels", BCP 14, RFC 2119, March 1997.

[7] Narten, T. and H. Alvestrand, "Guidelines for Writing an IANA
Considerations Section in RFCs", BCP 26, RFC 2434, October 1998.
[8] Farinacci, D., Li, T., Hanks, S., Meyer, D. and P. Traina,
"Generic Routing Encapsulation (GRE)", RFC 2784, March 2000.

[9] Montenegro, G., "Reverse Tunneling for Mobile IP, revised", RFC
3024, January 2001.

[10] Perkins, C., "IP Mobility Support for IPv4", RFC 3344, August
2002.

  1. Informative References

[11] Srisuresh, P. and M. Holdrege, "IP Network Address Translator
(NAT) Terminology and Considerations", RFC 2663, August 1999.

[12] Srisuresh, P. and K. Egevang, "Traditional IP Network Address
Translator (Traditional NAT)", RFC 3022, January 2001.

[13] Daigle, L., Editor, and IAB, "IAB Considerations for UNilateral
Self-Address Fixing (UNSAF)", RFC 3424, November 2002.

RFC4951

Fail Over Extensions for Layer 2 Tunneling Protocol (L2TP) "failover"
https://tools.ietf.org/html/rfc4951

  1. References

11.1. Normative References

[RFC2119] Bradner, S., "Key words for use in RFCs to Indicate
Requirement Levels", BCP 14, RFC 2119, March 1997.

[L2TPv2] Townsley, W., Valencia, A., Rubens, A., Pall, G.,
Zorn, G., and B. Palter, "Layer Two Tunneling Protocol
"L2TP"", RFC 2661, August 1999.

[L2TPv3] Lau, J., Townsley, M., and I. Goyret, "Layer Two
Tunneling Protocol - Version 3 (L2TPv3)", RFC 3931,
March 2005.

11.2. Informative References

[L2TPv2-MIB] Caves, E., Calhoun, P., and R. Wheeler, "Layer Two
Tunneling Protocol "L2TP" Management Information
Base", RFC 3371, August 2002.

[L2TPv3-MIB] Nadeau, T. and K. Koushik, "Layer Two Tunneling
Protocol (version 3) Management Information Base",
Work in Progress, August 2006.

[BFD-MULTIHOP] Katz, D. and D. Ward, "BFD for Multihop Paths", Work
in Progress, March 2007.

RFC 5515

Layer 2 Tunneling Protocol (L2TP) Access Line Information Attribute Value Pair (AVP) Extensions
https://tools.ietf.org/html/rfc5515

  1. References

11.1. Normative References

[RFC2119] Bradner, S., "Key words for use in RFCs to Indicate
Requirement Levels", BCP 14, RFC 2119, March 1997.

[RFC2661] Townsley, W., Valencia, A., Rubens, A., Pall, G., Zorn,
G., and B. Palter, "Layer Two Tunneling Protocol "L2TP"",
RFC 2661, August 1999.

[RFC3438] Townsley, W., "Layer Two Tunneling Protocol (L2TP)
Internet Assigned Numbers Authority (IANA) Considerations
Update", BCP 68, RFC 3438, December 2002.

[RFC3931] Lau, J., Townsley, M., and I. Goyret, "Layer Two Tunneling
Protocol - Version 3 (L2TPv3)", RFC 3931, March 2005.

[TR-101] DSL Forum, "Migration to Ethernet-Based DSL Aggregation",
TR 101, April 2006, technical/download/TR-101.pdf>.

11.2. Informative References

[ANCP] Wadhwa, S., Moisand, J., Subramanian, S., Haag, T., Voigt,
N., and R. Maglione, "Protocol for Access Node Control
Mechanism in Broadband Networks", Work in Progress,
March 2009.

[IANA.enterprise-numbers]
Internet Assigned Numbers Authority, "PRIVATE ENTERPRISE
NUMBERS", http://www.iana.org.

[IANA.l2tp-parameters]
Internet Assigned Numbers Authority, "Layer Two Tunneling
Protocol 'L2TP'", http://www.iana.org.

[RFC2516] Mamakos, L., Lidl, K., Evarts, J., Carrel, D., Simone, D.,
and R. Wheeler, "A Method for Transmitting PPP Over
Ethernet (PPPoE)", RFC 2516, February 1999.

[RFC3046] Patrick, M., "DHCP Relay Agent Information Option",
RFC 3046, January 2001.

[RFC3193] Patel, B., Aboba, B., Dixon, W., Zorn, G., and S. Booth,
"Securing L2TP using IPsec", RFC 3193, November 2001.

[RFC3629] Yergeau, F., "UTF-8, a transformation format of ISO
10646", STD 63, RFC 3629, November 2003.

[RFC4243] Stapp, M., Johnson, R., and T. Palaniappan, "Vendor-
Specific Information Suboption for the Dynamic Host
Configuration Protocol (DHCP) Relay Agent Option",
RFC 4243, December 2005.

[RFC4679] Mammoliti, V., Zorn, G., Arberg, P., and R. Rennison, "DSL
Forum Vendor-Specific RADIUS Attributes", RFC 4679,
September 2006.

[RFC4951] Jain, V., "Fail Over Extensions for Layer 2 Tunneling
Protocol (L2TP) "failover"", RFC 4951, August 2007.

RFC5641

Layer 2 Tunneling Protocol Version 3 (L2TPv3) Extended Circuit Status Values
https://www.rfc-editor.org/rfc/rfc5641.txt

  1. References

8.1. Normative References

[RFC2119] Bradner, S., "Key words for use in RFCs to Indicate
Requirement Levels", BCP 14, RFC 2119, March 1997.

[RFC3931] Lau, J., Townsley, M., and I. Goyret, "Layer Two
Tunneling Protocol - Version 3 (L2TPv3)", RFC 3931,
March 2005.

[RFC4349] Pignataro, C. and M. Townsley, "High-Level Data Link
Control (HDLC) Frames over Layer 2 Tunneling Protocol,
Version 3 (L2TPv3)", RFC 4349, February 2006.

[RFC4454] Singh, S., Townsley, M., and C. Pignataro, "Asynchronous
Transfer Mode (ATM) over Layer 2 Tunneling Protocol
Version 3 (L2TPv3)", RFC 4454, May 2006.

[RFC4591] Townsley, M., Wilkie, G., Booth, S., Bryant, S., and J.
Lau, "Frame Relay over Layer 2 Tunneling Protocol
Version 3 (L2TPv3)", RFC 4591, August 2006.

[RFC4719] Aggarwal, R., Townsley, M., and M. Dos Santos,
"Transport of Ethernet Frames over Layer 2 Tunneling
Protocol Version 3 (L2TPv3)", RFC 4719, November 2006.

8.2. Informative References

[IANA-l2tp] Internet Assigned Numbers Authority, "Layer Two
Tunneling Protocol 'L2TP'", http://www.iana.org.

[PREF-FWD] Muley, P., Bocci, M., and L. Martini, "Preferential
Forwarding Status bit definition", Work in Progress,
September 2008.

[RFC4446] Martini, L., "IANA Allocations for Pseudowire Edge to
Edge Emulation (PWE3)", BCP 116, RFC 4446, April 2006.

[RFC4447] Martini, L., Rosen, E., El-Aawar, N., Smith, T., and G.
Heron, "Pseudowire Setup and Maintenance Using the Label
Distribution Protocol (LDP)", RFC 4447, April 2006.

[RFC5085] Nadeau, T. and C. Pignataro, "Pseudowire Virtual Circuit
Connectivity Verification (VCCV): A Control Channel for
Pseudowires", RFC 5085, December 2007.

[VCCV-BFD] Nadeau, T. and C. Pignataro, "Bidirectional Forwarding
Detection (BFD) for the Pseudowire Virtual Circuit
Connectivity Verification (VCCV)", Work in Progress,
July 2009.

RFC 5905

Network Time Protocol Version 4: Protocol and Algorithms Specification
https://www.rfc-editor.org/rfc/rfc5905.txt

  1. References

18.1. Normative References

[RFC0768] Postel, J., "User Datagram Protocol", STD 6, RFC 768,
August 1980.

[RFC0791] Postel, J., "Internet Protocol", STD 5, RFC 791,
September 1981.

[RFC0793] Postel, J., "Transmission Control Protocol", STD 7,
RFC 793, September 1981.

[RFC1321] Rivest, R., "The MD5 Message-Digest Algorithm",
RFC 1321, April 1992.

[RFC2119] Bradner, S., "Key words for use in RFCs to Indicate
Requirement Levels", BCP 14, RFC 2119, March 1997.

18.2. Informative References

[CGPM] Bureau International des Poids et Mesures, "Comptes
Rendus de la 15e CGPM", 1976.

[ITU-R_TF.460] International Telecommunications Union, "ITU-R TF.460
Standard-frequency and time-signal emissions",
February 2002.

[RFC1305] Mills, D., "Network Time Protocol (Version 3)
Specification, Implementation and Analysis",
RFC 1305, March 1992.

[RFC1345] Simonsen, K., "Character Mnemonics and Character
Sets", RFC 1345, June 1992.

[RFC4330] Mills, D., "Simple Network Time Protocol (SNTP)
Version 4 for IPv4, IPv6 and OSI", RFC 4330,
January 2006.

[RFC5226] Narten, T. and H. Alvestrand, "Guidelines for Writing
an IANA Considerations Section in RFCs", BCP 26,
RFC 5226, May 2008.

[RFC5906] Haberman, B., Ed. and D. Mills, "Network Time
Protocol Version 4: Autokey Specification", RFC 5906,
June 2010.

[ref6] Marzullo and S. Owicki, "Maintaining the time in a
distributed system", ACM Operating Systems Review 19,
July 1985.

[ref7] Mills, D.L., "Computer Network Time Synchronization -
the Network Time Protocol", CRC Press, 304 pp, 2006.

[ref9] Mills, D.L., Electrical and Computer Engineering
Technical Report 06-6-1, NDSS, June 2006, "Network
Time Protocol Version 4 Reference and Implementation
Guide", 2006.

RFC 5944

IP Mobility Support for IPv4, Revised
https://www.rfc-editor.org/rfc/rfc3193.txt

  1. References

8.1. Normative References

[1] Bradner, S., "Key words for use in RFCs to Indicate Requirement
Levels", BCP 14, RFC 2119, March 1997.

[2] Calhoun, P. and C. Perkins, "Mobile IP Network Access
Identifier Extension for IPv4", RFC 2794, March 2000.

[3] Perkins, C., Calhoun, P., and J. Bharatia, "Mobile IPv4
Challenge/Response Extensions (Revised)", RFC 4721, January
2007.

[4] Cong, D., Hamlen, M., and C. Perkins, "The Definitions of
Managed Objects for IP Mobility Support using SMIv2", RFC 2006,
October 1996.

[5] Deering, S., Ed., "ICMP Router Discovery Messages", RFC 1256,
September 1991.

[6] Deering, S., "Host extensions for IP multicasting", STD 5, RFC
1112, August 1989.

[7] Dommety, G. and K. Leung, "Mobile IP Vendor/Organization-
Specific Extensions", RFC 3115, April 2001.

[8] Eastlake 3rd, D., Schiller, J., and S. Crocker, "Randomness
Requirements for Security", BCP 106, RFC 4086, June 2005.

[9] Kent, S., "IP Authentication Header", RFC 4302, December 2005.

[10] Krawczyk, H., Bellare, M., and R. Canetti, "HMAC: Keyed-Hashing
for Message Authentication", RFC 2104, February 1997.

[11] Mills, D., Martin, J., Ed., Burbank, J., and W. Kasch, "Network
Time Protocol Version 4: Protocol and Algorithms
Specification", RFC 5905, June 2010.

[12] Montenegro, G., Ed., "Reverse Tunneling for Mobile IP,
revised", RFC 3024, January 2001.

[13] Farinacci, D., Li, T., Hanks, S., Meyer, D., and P. Traina,
"Generic Routing Encapsulation (GRE)", RFC 2784, March 2000.

[14] Perkins, C., "IP Encapsulation within IP", RFC 2003, October
1996.

[15] Perkins, C., "Minimal Encapsulation within IP", RFC 2004,
October 1996.

[16] Plummer, D., "Ethernet Address Resolution Protocol: Or
Converting Network Protocol Addresses to 48.bit Ethernet
Address for Transmission on Ethernet Hardware", STD 37, RFC
826, November 1982.

[17] Postel, J., "User Datagram Protocol", STD 6, RFC 768, August
1980.

[18] Postel, J., "Internet Protocol", STD 5, RFC 791, September
1981.

[19] Rivest, R., "The MD5 Message-Digest Algorithm", RFC 1321, April
1992.

[20] Solomon, J., "Applicability Statement for IP Mobility Support",
RFC 2005, October 1996.

[21] Perkins, C., Ed., "IP Mobility Support for IPv4", RFC 3344,
August 2002.

[22] Narten, T. and H. Alvestrand, "Guidelines for Writing an IANA
Considerations Section in RFCs", BCP 26, RFC 5226, May 2008.

8.2. Informative References

[23] Solomon, J. and S. Glass, "Mobile-IPv4 Configuration Option for
PPP IPCP", RFC 2290, February 1998.

[24] Montenegro, G., Dawkins, S., Kojo, M., Magret, V., and N.
Vaidya, "Long Thin Networks", RFC 2757, January 2000.

[25] Allman, M., Glover, D., and L. Sanchez, "Enhancing TCP Over
Satellite Channels using Standard Mechanisms", BCP 28, RFC
2488, January 1999.

[26] Paxson, V. and M. Allman, "Computing TCP's Retransmission
Timer", RFC 2988, November 2000.

[27] Levkowetz, H. and S. Vaarala, "Mobile IP Traversal of Network
Address Translation (NAT) Devices", RFC 3519, April 2003.

[28] Glass, S. and M. Chandra, "Registration Revocation in Mobile
IPv4", RFC 3543, August 2003.

[29] Fogelstroem, E., Jonsson, A., and C. Perkins, "Mobile IPv4
Regional Registration", RFC 4857, June 2007.

[30] Bellovin, S., "Security Problems in the TCP/IP Protocol Suite",
ACM Computer Communications Review, 19(2), March 1989.

[31] Border, J., Kojo, M., Griner, J., Montenegro, G., and Z.
Shelby, "Performance Enhancing Proxies Intended to Mitigate
Link-Related Degradations", RFC 3135, June 2001.

[32] Caceres, R. and L. Iftode, "Improving the Performance of
Reliable Transport Protocols in Mobile Computing Environments",
IEEE Journal on Selected Areas in Communication, 13(5):850-857,
June 1995.

[33] Dawkins, S., Montenegro, G., Kojo, M., Magret, V., and N.
Vaidya, "End-to-end Performance Implications of Links with
Errors", BCP 50, RFC 3155, August 2001.

[34] Droms, R., "Dynamic Host Configuration Protocol", RFC 2131,
March 1997.

[35] Ferguson, P. and D. Senie, "Network Ingress Filtering:
Defeating Denial of Service Attacks which employ IP Source
Address Spoofing", BCP 38, RFC 2827, May 2000.

[36] Jacobson, V., "Compressing TCP/IP Headers for Low-Speed Serial
Links", RFC 1144, February 1990.

[37] Ioannidis, J., Duchamp, D., and G. Maguire, "IP-Based Protocols
for Mobile Internetworking", In Proceedings of the SIGCOMM '01
Conference: Communications Architectures and Protocols, pages
235-245, September 1991.

[38] Ioannidis, J. and G. Maguire, "The Design and Implementation of
a Mobile Internetworking Architecture", In Proceedings of the
Winter USENIX Technical Conference, pages 489-500, January
1993.

[39] Ioannidis, J., "Protocols for Mobile Internetworking", PhD
Dissertation - Columbia University in the City of New York,
July 1993.

[40] Jacobson, V., "Congestion Avoidance and Control", In
Proceedings of the SIGCOMM '88 Workshop, ACM SIGCOMM, ACM
Press, pages 314-329, August 1998.

[41] McCloghrie, K. and F. Kastenholz, "The Interfaces Group MIB",
RFC 2863, June 2000.

[42] McGregor, G., "The PPP Internet Protocol Control Protocol
(IPCP)", RFC 1332, May 1992.

[43] Montenegro, G. and V. Gupta, "Sun's SKIP Firewall Traversal for
Mobile IP", RFC 2356, June 1998.

[44] Perkins, C., Ed., "IP Mobility Support", RFC 2002, October
1996.

[45] Stevens, R., "TCP/IP Illustrated, Volume 1: The Protocols",
Addison-Wesley, Reading, Massachusetts, 1994.

[46] Perkins, C. and P. Calhoun, "Authentication, Authorization, and
Accounting (AAA) Registration Keys for Mobile IPv4", RFC 3957,
March 2005.

[47] Simpson, W., Ed., "The Point-to-Point Protocol (PPP)", STD 51,
RFC 1661, July 1994.

[48] IANA, "Mobile IPv4 Numbers", http://www.iana.org.

[49] Postel, J., "Multi-LAN address resolution", RFC 925, October
1984.

[50] Perkins, C., Ed., "IP Mobility Support for IPv4", RFC 3220,
January 2002.

RFC 6169

Security Concerns with IP Tunneling
https://www.rfc-editor.org/rfc/rfc6169.txt
10. Informative References

[RFC2529] Carpenter, B. and C. Jung, "Transmission of IPv6 over IPv4
Domains without Explicit Tunnels", RFC 2529, March 1999.

[RFC2661] Townsley, W., Valencia, A., Rubens, A., Pall, G., Zorn,
G., and B. Palter, "Layer Two Tunneling Protocol "L2TP"",
RFC 2661, August 1999.

[RFC2979] Freed, N., "Behavior of and Requirements for Internet
Firewalls", RFC 2979, October 2000.

[RFC3056] Carpenter, B. and K. Moore, "Connection of IPv6 Domains
via IPv4 Clouds", RFC 3056, February 2001.

[RFC3484] Draves, R., "Default Address Selection for Internet
Protocol version 6 (IPv6)", RFC 3484, February 2003.

[RFC3931] Lau, J., Ed., Townsley, M., Ed., and I. Goyret, Ed.,
"Layer Two Tunneling Protocol - Version 3 (L2TPv3)", RFC
3931, March 2005.

[RFC3971] Arkko, J., Ed., Kempf, J., Zill, B., and P. Nikander,
"SEcure Neighbor Discovery (SEND)", RFC 3971, March 2005.
[RFC4380] Huitema, C., "Teredo: Tunneling IPv6 over UDP through
Network Address Translations (NATs)", RFC 4380, February
2006.

[RFC4787] Audet, F., Ed., and C. Jennings, "Network Address
Translation (NAT) Behavioral Requirements for Unicast
UDP", BCP 127, RFC 4787, January 2007.

[RFC5095] Abley, J., Savola, P., and G. Neville-Neil, "Deprecation
of Type 0 Routing Headers in IPv6", RFC 5095, December
2007.

[RFC5214] Templin, F., Gleeson, T., and D. Thaler, "Intra-Site
Automatic Tunnel Addressing Protocol (ISATAP)", RFC 5214,
March 2008.

[RFC5389] Rosenberg, J., Mahy, R., Matthews, P., and D. Wing,
"Session Traversal Utilities for NAT (STUN)", RFC 5389,
October 2008.

[RFC5991] Thaler, D., Krishnan, S., and J. Hoagland, "Teredo
Security Updates", RFC 5991, September 2010.

[RFC6056] Larsen, M. and F. Gont, "Recommendations for Transport-
Protocol Port Randomization", BCP 156, RFC 6056, January
2011.

[SECA-IP] Gont, F., "Security Assessment of the Internet Protocol
version 4", Work in Progress, April 2011.

[TUNNEL-LOOPS]
Nakibly, G. and F. Templin, "Routing Loop Attack using
IPv6 Automatic Tunnels: Problem Statement and Proposed
Mitigations", Work in Progress, March 2011.

RFC6758

Tunneling of SMTP Message Transfer Priorities
https://www.rfc-editor.org/rfc/rfc6758.txt

  1. References

8.1. Normative References

[RFC2119] Bradner, S., "Key words for use in RFCs to Indicate
Requirement Levels", BCP 14, RFC 2119, March 1997.

[RFC3461] Moore, K., "Simple Mail Transfer Protocol (SMTP) Service
Extension for Delivery Status Notifications (DSNs)",
RFC 3461, January 2003.

[RFC5234] Crocker, D. and P. Overell, "Augmented BNF for Syntax
Specifications: ABNF", STD 68, RFC 5234, January 2008.

[RFC5321] Klensin, J., "Simple Mail Transfer Protocol", RFC 5321,
October 2008.

[RFC5322] Resnick, P., Ed., "Internet Message Format", RFC 5322,
October 2008.

[RFC6409] Gellens, R. and J. Klensin, "Message Submission for Mail",
STD 72, RFC 6409, November 2011.

[RFC6710] Melnikov, A. and K. Carlberg, "Simple Mail Transfer
Protocol Extension for Message Transfer Priorities",
RFC 6710, August 2012.

8.2. Informative References

[RFC2156] Kille, S., "MIXER (Mime Internet X.400 Enhanced Relay):
Mapping between X.400 and RFC 822/MIME", RFC 2156,
January 1998.

[RFC3207] Hoffman, P., "SMTP Service Extension for Secure SMTP over
Transport Layer Security", RFC 3207, February 2002.

[RFC6376] Crocker, D., Hansen, T., and M. Kucherawy, "DomainKeys
Identified Mail (DKIM) Signatures", RFC 6376,
September 2011.

[SMTP-PRI-OLD]
Schmeing, M., Brendecke, J., and K. Carlberg, "SMTP
Service Extension for Priority Message Handling", Work
in Progress, August 2006.

RFC7450

Automatic Multicast Tunneling
https://www.rfc-editor.org/rfc/rfc7450.txt

  1. References

8.1. Normative References

[RFC2119] Bradner, S., "Key words for use in RFCs to Indicate
Requirement Levels", BCP 14, RFC 2119, March 1997,
http://www.rfc-editor.org/info/rfc2119.

[RFC3376] Cain, B., Deering, S., Kouvelas, I., Fenner, B., and A.
Thyagarajan, "Internet Group Management Protocol,
Version 3", RFC 3376, October 2002,
http://www.rfc-editor.org/info/rfc3376.

[RFC3810] Vida, R., Ed., and L. Costa, Ed., "Multicast Listener
Discovery Version 2 (MLDv2) for IPv6", RFC 3810,
June 2004, http://www.rfc-editor.org/info/rfc3810.

[RFC4291] Hinden, R. and S. Deering, "IP Version 6 Addressing
Architecture", RFC 4291, February 2006,
http://www.rfc-editor.org/info/rfc4291.

[RFC4607] Holbrook, H. and B. Cain, "Source-Specific Multicast for
IP", RFC 4607, August 2006,
http://www.rfc-editor.org/info/rfc4607.

[RFC4787] Audet, F., Ed., and C. Jennings, "Network Address
Translation (NAT) Behavioral Requirements for Unicast
UDP", BCP 127, RFC 4787, January 2007,
http://www.rfc-editor.org/info/rfc4787.

8.2. Informative References

[RFC0791] Postel, J., "Internet Protocol", STD 5, RFC 791,
September 1981, http://www.rfc-editor.org/info/rfc0791.

[RFC0792] Postel, J., "Internet Control Message Protocol", STD 5,
RFC 792, September 1981,
http://www.rfc-editor.org/info/rfc0792.

[RFC1112] Deering, S., "Host extensions for IP multicasting", STD 5,
RFC 1112, August 1989,
http://www.rfc-editor.org/info/rfc1112.

[RFC1191] Mogul, J. and S. Deering, "Path MTU discovery", RFC 1191,
November 1990, http://www.rfc-editor.org/info/rfc1191.

[RFC1546] Partridge, C., Mendez, T., and W. Milliken, "Host
Anycasting Service", RFC 1546, November 1993,
http://www.rfc-editor.org/info/rfc1546.

[RFC1981] McCann, J., Deering, S., and J. Mogul, "Path MTU Discovery
for IP version 6", RFC 1981, August 1996,
http://www.rfc-editor.org/info/rfc1981.

[RFC2236] Fenner, W., "Internet Group Management Protocol,
Version 2", RFC 2236, November 1997,
http://www.rfc-editor.org/info/rfc2236.

[RFC2460] Deering, S. and R. Hinden, "Internet Protocol, Version 6
(IPv6) Specification", RFC 2460, December 1998,
http://www.rfc-editor.org/info/rfc2460.

[RFC2663] Srisuresh, P. and M. Holdrege, "IP Network Address
Translator (NAT) Terminology and Considerations",
RFC 2663, August 1999,
http://www.rfc-editor.org/info/rfc2663.

[RFC2710] Deering, S., Fenner, W., and B. Haberman, "Multicast
Listener Discovery (MLD) for IPv6", RFC 2710,
October 1999, http://www.rfc-editor.org/info/rfc2710.

[RFC3552] Rescorla, E. and B. Korver, "Guidelines for Writing RFC
Text on Security Considerations", BCP 72, RFC 3552,
July 2003, http://www.rfc-editor.org/info/rfc3552.

[RFC4271] Rekhter, Y., Ed., Li, T., Ed., and S. Hares, Ed., "A
Border Gateway Protocol 4 (BGP-4)", RFC 4271,
January 2006, http://www.rfc-editor.org/info/rfc4271.

[RFC4443] Conta, A., Deering, S., and M. Gupta, Ed., "Internet
Control Message Protocol (ICMPv6) for the Internet
Protocol Version 6 (IPv6) Specification", RFC 4443,
March 2006, http://www.rfc-editor.org/info/rfc4443.

[RFC4601] Fenner, B., Handley, M., Holbrook, H., and I. Kouvelas,
"Protocol Independent Multicast - Sparse Mode (PIM-SM):
Protocol Specification (Revised)", RFC 4601, August 2006,
http://www.rfc-editor.org/info/rfc4601.

[RFC4786] Abley, J. and K. Lindqvist, "Operation of Anycast
Services", BCP 126, RFC 4786, December 2006,
http://www.rfc-editor.org/info/rfc4786.

[RFC6935] Eubanks, M., Chimento, P., and M. Westerlund, "IPv6 and
UDP Checksums for Tunneled Packets", RFC 6935, April 2013,
http://www.rfc-editor.org/info/rfc6935.

[RFC6936] Fairhurst, G. and M. Westerlund, "Applicability Statement
for the Use of IPv6 UDP Datagrams with Zero Checksums",
RFC 6936, April 2013,
http://www.rfc-editor.org/info/rfc6936.

RFC 7886

Advertising Seamless Bidirectional Forwarding Detection (S-BFD) Discriminators in the Layer Two Tunneling Protocol Version 3 (L2TPv3)
https://www.rfc-editor.org/rfc/rfc7886.txt

  1. References

5.1. Normative References

[RFC2119] Bradner, S., "Key words for use in RFCs to Indicate
Requirement Levels", BCP 14, RFC 2119,
DOI 10.17487/RFC2119, March 1997,
http://www.rfc-editor.org/info/rfc2119.

[RFC3438] Townsley, W., "Layer Two Tunneling Protocol (L2TP)
Internet Assigned Numbers Authority (IANA) Considerations
Update", BCP 68, RFC 3438, DOI 10.17487/RFC3438,
December 2002, http://www.rfc-editor.org/info/rfc3438.

[RFC3931] Lau, J., Ed., Townsley, M., Ed., and I. Goyret, Ed.,
"Layer Two Tunneling Protocol - Version 3 (L2TPv3)",
RFC 3931, DOI 10.17487/RFC3931, March 2005,
http://www.rfc-editor.org/info/rfc3931.

[RFC7880] Pignataro, C., Ward, D., Akiya, N., Bhatia, M., and S.
Pallagatti, "Seamless Bidirectional Forwarding Detection
(S-BFD)", RFC 7880, DOI 10.17487/RFC7880, July 2016,
http://www.rfc-editor.org/info/rfc7880.

5.2. Informative References

[RFC5880] Katz, D. and D. Ward, "Bidirectional Forwarding Detection
(BFD)", RFC 5880, DOI 10.17487/RFC5880, June 2010,
http://www.rfc-editor.org/info/rfc5880.

参考資料(reference)

RFC search
https://www.rfc-editor.org/search/rfc_search.php

文書履歴(document history)

ver. 0.01 初稿 20200103
ver. 0.02 RFC追記 20200211

【PHP8】もう`strpos($haystack, $needle)!==false`って書かなくていいんだ

ある文字列中に特定の文字列が存在するかを調べる方法としてstrposが存在します。

しかし、そもそもstrposは『ある文字列中で特定の文字列が何文字目に出てくるか』を調べる関数であり、第一に使用目的が異なる関数です。
そしてこちらも有名な話ですが、先頭が一致すると0が返ってくるので、緩やかな比較ではfalseと区別されません。
PHPのよくある落とし穴のひとつです。

if(strpos('放課後アトリエといろ','アトリエ')){echo'"放課後アトリエといろ"には"アトリエ"が含まれる';// 表示される}if(strpos('放課後アトリエといろ','放課後')){echo'"放課後アトリエといろ"には"放課後"が含まれる';// 表示されない!!}if(strpos('放課後アトリエといろ','放課後')!==false){echo'"放課後アトリエといろ"には"放課後"が含まれる';// 表示される}

マニュアルにも大きく警告が出されています。
01.png

この状況がついにPHP8で変わります

PHP RFC: str_contains

Introduction

str_containsは、ある文字列に特定の文字列が含まれているかをチェックし、見つかったか否かによってtrue/falseいずれかのbooleanを返します。

ある文字列に特定の文字列が含まれているかをチェックするために、一般的にはstrposstrstrが使用されます。
str_containsは凡そあらゆるプロジェクトで非常によく使われるユースケースなので、独自の関数を追加するに値するはずです。
strposstrstrには、いくつかの欠点が存在します。

・あまり直感的ではない
・間違いをしやすい(特に!==の場合)
・新規PHP開発者が覚えにくい

このため、多くのPHPフレームワークは独自のヘルパ関数を提供しています。
このことこそがstr_containsの重要性や必要性をよく示しています。

Proposal

このRFCは、新しい関数str_containsを提唱します。

str_contains(string$haystack,string$needle):bool

引数$haystack$needleを取り、$haystackの中に$needleが存在するか否かをbooleanで返します。

str_contains("abc","a");// truestr_contains("abc","d");// false// 空文字列はtrueになるstr_contains("abc","");// truestr_contains("","");// true

空文字列の扱いについて

As of PHP 8, behavior of '' in string search functions is well defined, and we consider '' to occur at every position in the string, including one past the end. As such, both of these will (or at least should) return true. The empty string is contained in every string.

PHP8において、文字列検索関数において''の動作は明確に定義されており、終端を含む文字列全ての位置にマッチします。そのため、これらは両方ともtrueを返すべきです。空文字列はあらゆる文字列に含まれています。 - Nikita Popov

Case-insensitivity and multibyte strings

internalメーリングリストなどの議論において、この関数のマルチバイト対応版(mb_str_contains)は必要ないという結論に達しました。
理由として、この関数のマルチバイト版は非マルチバイト版と全く同じ動作になります。
文字列の見付かった位置によって動作が異なる場合は、マルチバイト版は異なる動作になります。
この関数は見付かった位置によって動作は変わらないので、マルチバイト版の必要はありません。

大文字と小文字を区別しない版については、需要が大文字と小文字を区別する版よりはるかに低いため、このRFCには含まれません。
区別しない版を取り込むと、有効なバリアントはstr_contains/mb_str_icontainsだけになります。
このように中途半端なバリアントをいきなり提供するとPHP開発者が混乱する可能性があるので、最初は小さく始めた方がよいでしょう。

Backward Incompatible Changes

PHP自体に後方互換性のない変更はありません。

ユーザランドに同じ関数が実装されている場合、非互換の可能性があります。
しかし、そのようなグローバル関数はアプリケーションの起動プロセスのかなり早い段階で追加されるので、開発者はこの問題にすぐ気付くでしょう。

Proposed PHP Version(s)

PHP 8

Implementation

str_contains関数は、このプルリクで実装されています。
https://github.com/php/php-src/pull/5179

投票

投票は2020/03/16まで、受理には2/3の賛成が必要です。
2020/03/09時点では賛成43反対5で、まず間違いなく受理されます。

感想

よく考えたらずっと前からあってもおかしくない関数なのに、これまで存在してなかったのは不思議ですね。

実際のところ、文字数としてはわずか2字の差にすぎません。

if(strpos($heystack,$needle)!==false){echo'$heystackに$needleが含まれている';}// 同じif(str_contains($heystack,$needle)){echo'$heystackに$needleが含まれている';}

しかし、読みやすさ、理解のしやすさという点では圧倒的にstr_containsに分がありますね。

以下はマルチバイト対応関数が用意されない点の補足です。
マルチバイト対応strposとしてmb_strposがありますが、文字が存在するか否かをチェックするだけであれば実はstrposでも問題ありません。

echostrpos('あい','い');// 3echomb_strpos('あい','い');// 1echostrpos('あい','あ');// 0echomb_strpos('あい','あ');// 0echostrpos('あい','う');// falseechomb_strpos('あい','う');// false

値が変わるのは『存在したときの文字数の数え方』だけです。
文字列の有無を確認するだけであれば、存在しない場合は常にfalse、存在する場合は常にint型となって差が出ないわけですね。

同様にstr_containsも、存在しない場合は常にfalse、存在する場合は常にtrueなるため、あえてmb_str_containsを用意する必要はないというわけです。

Set-Cookieが不正な文字列、もしくは解釈が自明でない場合の挙動について

Webには状態を管理する方法の1つとして、Cookie(クッキー)があるのはご存知かと思います。
このCookieは、サーバーから送信されるSet-Cookieと呼ばれるHTTPレスポンスヘッダを用いてクライアント側に保存されるものです。

ここでは、Set-Cookieが不正な文字列、もしくはその解釈が自明でないような文字列であった場合、クライアント(Webブラウザ)がどのように振る舞うのかをRFC6265をナナメ読みしつつ追っていきます。

Cookieの仕様

Cookieに関する仕様はRFC6265 - HTTP State Management Mechanismに定められています。

Set-Cookieの文法

Set-Cookieが不正な文字列の場合」と言いましたが、そもそもSet-Cookieがどういう文字列であればValidであり、またはInvalidなんでしょうか?
これは4.1.1. Syntaxに書かれています。

set-cookie-header="Set-Cookie:"SP set-cookie-stringset-cookie-string=cookie-pair *( ";" SP cookie-av )cookie-pair=cookie-name "=" cookie-valuecookie-name=tokencookie-value=*cookie-octet / ( DQUOTE *cookie-octet DQUOTE )cookie-octet=%x21 / %x23-2B / %x2D-3A / %x3C-5B / %x5D-7E; US-ASCII characters excluding CTLs,
; whitespace DQUOTE, comma, semicolon,
; and backslash
token=<token, defined in [RFC2616], Section 2.2>cookie-av=expires-av / max-age-av / domain-av /path-av/secure-av/httponly-av/extension-avexpires-av="Expires="sane-cookie-datesane-cookie-date=<rfc1123-date, defined in [RFC2616], Section 3.3.1>max-age-av="Max-Age="non-zero-digit *DIGIT; In practice, both expires-av and max-age-av
; are limited to dates representable by the
; user agent.
non-zero-digit=%x31-39; digits 1 through 9
domain-av="Domain="domain-valuedomain-value=<subdomain>; defined in [RFC1034], Section 3.5, as
; enhanced by [RFC1123], Section 2.1
path-av="Path="path-valuepath-value=<any CHAR except CTLs or ";">secure-av="Secure"httponly-av="HttpOnly"extension-av=<any CHAR except CTLs or ";">

これはABNFと呼ばれるものです。
記法の意味は👆のリンク先を参照してください。

コレに従うとすると、以下のようなSet-CookieはValidで……

Set-Cookie:Cookie=IsYummy; Secure

一方で、例えば以下のようなものはInvalidです。1

# 名前がRFC2616のtoken定義を満たしていない(separatorsであるカッコを用いることはできない)Set-Cookie:Co(o)kie=IsYummy# *cookie-octet に whitespace は含まれない(たとえDQUOTEで囲われていても)Set-Cookie:Cookie=is yummySet-Cookie:Cookie="is yummy"# 必ず ; の後に SP が必要Set-Cookie:Cookie=IsYummy;Secure# 末尾の ; が余計Set-Cookie:Cookie=IsYummy; HttpOnly;# Max-Age の1文字目は 0 であってはならないSet-Cookie:Cookie=IsYummy; Max−Age=01

そもそも、RFC6265の本節には「文法を満たさないSet-Cookieヘッダを送るべきではない(SHOULD NOT)」と書かれていますが、様々な理由によって不正なSet-Cookieが送信されてしまうことがあります。
実際の例については、本記事の末尾で触れます。

Set-CookieのSemantics

4.1.2. Semanticsでは、各cookie-av(後ろにくっついているPath=/のような属性のこと)の意味が定義されています。

ここで1つ気になるのは、例えば以下のようなSet-Cookieはどのように解釈されるのか?という点です。

Set-Cookie:Cookie=IsYummy; Max−Age=123; Max-Age=456Set-Cookie:Cookie=IsYummy; Path=/abc; Path=/def

これらは、Syntax的にはValidなものですが、ブラウザがどのように解釈するべきなのか自明ではありません。

Set-Cookieのパース

5.2. The Set-Cookie Headerでは、Set-Cookieを受け取ったUser Agent(ブラウザ)がどのようにCookieを処理すべきが具体的に書かれています。

注目すべきなのは、ここで定義されている処理法がだいぶPermissiveであり、4.1.1. Syntaxで示されたSyntaxを満たさないSet-Cookieであっても受理できる点です。

詳しくはRFC6265の5.2.を参照していただきたいのですが、ざっくり書いておくと以下のような流れです。
例えばSet-Cookie: Cookie = IsYummy; Max-Age = 810を受け取った場合の動作も書き添えておきます。これは無駄なSPが入っているためInvalidなSyntaxですが、受理されるでしょうか?

  1. Set-Cookieヘッダの内容について、最初の;までを取り出す。もし;が見つからない場合は最後まで取り出す。これをname-value-pairとする。取り出した残りの文字列はunparsed-attributesとする。
    • name-value-pair := "Cookie = IsYummy"
    • unparsed-attributes := "; Max-Age = 810"
  2. name-value-pairに=が見つからなかった場合、そのSet-Cookieを無視する。
  3. name-value-pairの最初の=までをname-stringとする。最初の=より後をvalue-stringとする。このときはどちらも空文字列であってもOK。
    • name-string := "Cookie "
    • value-string := " IsYummy"
  4. name-stringとvalue-stringのそれぞれから、先頭・末尾にある空白文字を削除する。
    • name-string <- "Cookie"
    • value-string <- "IsYummy"
  5. ここでname-stringが空白になった場合、そのSet-Cookieを無視する。
  6. name-stringがこのCookieの名前で、value-stringのこのCookieの値である。
  7. unparsed-attributesが空白の場合、ここで終了。
  8. unparsed-attributesの最初の文字列を捨てる。これは必ず;であるはず。
    • unparsed-attributes <- " Max-Age = 810"
  9. unparsed-attributesについて、最初の;までを取り出す。もし;が見つからない場合は最後まで取り出す。これをcookie-avとする。
    • unparsed-attributes <- ""
    • cookie-av := " Max-Age = 810"
  10. cookie-avの最初の=までをattribute-nameとする。最初の=より後をattribute-valueとする。このときはどちらも空文字列であってもOK。もし=が見つからない場合はcookie-avの全体をattribute-nameとする。
    • attribute-name := " Max-Age "
    • attribute-value := " 810"
  11. attribute-nameとattribute-valueのそれぞれから、先頭・末尾にある空白文字を削除する。
    • attribute-name <- "Max-Age"
    • attribute-value <- "810"
  12. 5.2.x.節の内容に従ってattributeを処理する。
    • 省略
  13. cookie-attribute-listの末尾にattribute-nameとattribute-valueのペアを追加する。
    • cookie-attribute-list := [ ("Max-Age", "810") ]
  14. Step.7から繰り返し。
    • 戻ってすぐ終了

このようにSyntaxに従わないSet-Cookieでも、ある程度は受理できそうなことがわかります。

ストレージモデル

5.3. Storage Modelでは、Cookieを受理したブラウザがどのようにCookieを保管すべきかが書かれています。

先述したどのように解釈するべきなのか自明でないCookieですが、本節を読むとこの解釈の答えが見つかります。
たとえば、Max-Ageが複数あった場合の解釈はどうすべきなのかを要点だけ抜き出して書くと、以下の通りになります。

  • まず、保存されるCookieはexpiry-timeという属性を持つ
  • もしcookie-attribute-listにMax-Ageというattribute-nameを持つ要素が含まれていたなならば……
    • cookie-attribute-listでMax-Ageというattribute-nameを持つ最後の要素のattribute-valueをCookieのexpiry-timeへ設定する

他の属性についても、基本的にはこのようにcookie-attribute-listの最後の要素を使うように書かれています。

cookie-attribute-listは、Set-Cookieのパース中は必ず末尾に要素が追加されていくものでした。
つまり、Set-Cookieに同じ属性があった場合、後に出てきた要素が優先されるのが正解です。

実際のブラウザの挙動

Set-Cookieが不正、もしくは解釈が自明でない場合の動作は、RFC6265を読むことで大方見えてきました。
では、世の中のブラウザは実際どのように振る舞うのかを見ていきましょう。

ブラウザの実装をソースコードから探す気力はなかったので、実際に変なSet-Cookieを投げつけて挙動を確認することにします。。。

以下のようなPHPコードをつかって、ダメなSet-Cookieをブラウザに食わせてみました。

<?php// Case 1: Syntaxが不正だが受理されるはずheader("Set-Cookie: Inva(l)idToken=Inva(l)idToken",false);// Case 2: Syntaxが不正だが受理されるはずheader("Set-Cookie: Has Whitespace=Has Whitespace",false);// Case 3: Syntaxが不正で無視されるはずheader("Set-Cookie: =NoName",false);// Case 4: Syntaxが不正だが受理され、HttpOnlyが有効になるはずheader("Set-Cookie: InvalidSyntax=InvalidSyntax;HttpOnly;",false);// Case 5: Path=/B になるはずheader("Set-Cookie: MultiPath=MultiPath; Path=/A; Path=/B",false);?>

結果

Firefox 74 と Chrome 80 と Safari 13 でそれぞれ実験しました。結果は以下の表の通りです。

RFCFirefox 74Chrome 80Safari 13
Case 1受理受理受理受理
Case 2受理受理受理受理
Case 3無視受理受理無視
Case 4受理/HttpOnly受理/HttpOnly受理/HttpOnly受理/HttpOnly
Case 5Path=/BPath=/BPath=/BPath=/B

概ね想定通りでしたが、cookie-nameが空白のCookieの取り扱いについて、SafariはRFCに従っていたものの、FirefoxとChromeは無視されるべきものを受理していました。

以下はエビデンス画像です。

Firefox 74

firefox.png

Chrome 80

chrome.png

Safari 13

safari.png

どんな場合にSet-Cookieが不正な文字列、もしくは解釈が自明でない文字列になるか

私が遭遇したシチュエーションが以下です。

  • nginxをリバースプロキシとして用いている
  • Chrome 80からSameSite属性が未指定の場合、デフォルトでSameSite=Laxとして取り扱われることになった
  • アプリが想定外の挙動をしたので、従来の挙動SameSite=Noneに戻したい
  • しかしアプリには手を加えたくない
  • ので、nginxでCookieを書き換えてSameSite=Noneを追加することにした

nginxでこれをやろうとしたとき、proxy_cookie_path directiveを使う方法があります。
これは、その名前の通りCookieのPath属性を書き換えるものなのですが、実は以下のように指定すると別の属性を追加することができる2という、だいぶ怪しい使い方があります。

proxy_cookie_path / "/; SameSite=strict";

これを導入すると、とりあえず目的は達成されるのですが、全てのCookieに同じSameSiteをつけることしかできませんし、あとから気が変わってアプリ側でSameSiteを付与することになった場合、SameSite属性が重複することになってしまうのです。。。

ちなみに

SameSiteは比較的新しいCookieの仕様で、RFC6265にはまだ含まれていません。
新しい仕様の草稿draft-ietf-httpbis-rfc6265bisに含まれています。

このSameSiteが重複していたときの取り扱いについて、rfc6265bisの02版ではcookie-attribute-listの最後の要素を使う旨の文が抜けており、曖昧性を残していて気持ちが悪かったのですが、04版ではちゃんと修正され、他の属性同様に最後の要素を使うようになりました。
実際にブラウザで試しても最後の要素が選択されます。


  1. この文法定義は曖昧性を残しており、たとえば最後の例は extension-av であるとみなすならばValidです。 

  2. https://serverfault.com/questions/849888/add-samesite-to-cookies-using-nginx-as-reverse-proxy 

【PHP8.0】gettypeとget_classの悪魔合体

ワレハget_debug_type、コンゴトモヨロシク…

PHPにはプリミティブ型名を取得するgettypeと、オブジェクトのクラス名を返すget_classという関数が存在します。
_があったりなかったりと命名の不統一も気になりますが、それよりgettypeはオブジェクトに使うとobjectしか返さず、get_classをプリミティブ型に使うとE_WARNINGが発生します。
いや、プリミティブ型であればintとかの型が欲しいし、オブジェクトならPDOとかの型が欲しいんだ、という問題に対する答えはありませんでした。

というわけで両者を合体させたget_debug_typeというRFCが提出されました。

PHP RFC: get_debug_type

proposal

このRFCは、指定された変数の型を返す新しい関数、get_debug_typeを追加する提案です。

これは、配列で来る値など、変数の型に基づいた既存のチェック方法では対応できないパターンを置き換えるためのものです。

$bar=$arr['key'];if(!($barinstanceofFoo)){// もっとも単純な例。しかしgettypeは"integer"を返すので、正しい型にしたいなら"int"に変換するなどが必要。thrownewTypeError('Expected '.Foo::class.' got '.(is_object($bar)?get_class($bar):gettype($bar)));}// 今後はこう書けるif(!($barinstanceofFoo)){thrownewTypeError('Expected '.Foo::class.' got '.get_debug_type($bar));}$bar->someFooMethod();

この関数は、正しい型名を返すという点でgettypeと異なります。
"integer"ではなく"int"を返し、クラスもクラス名に変換します。
次の表は、いくつかの値に対してgettypeget_debug_typeが返す値を比較したものです。

get_debug_type()gettype()
0intinteger
0.1floatdouble
trueboolboolean
falseboolboolean
"hello"string
[]array
nullnullNULL
Foo\BarFoo\Barobject
無名クラスclass@anonymousobject
リソースresource (xxx)resource
閉じたリソースresource (closed)

Backward Incompatible Changes

なし。

Proposed PHP Version(s)

PHP8.0

Implementation

https://github.com/php/php-src/pull/5143

投票

投票は2020/03/26まで、2/3の賛成で受理されます。
このRFCは賛成42、反対3で受理されました。

感想

Mark Randallは最初はgettypeがクラス名も返すようにしようとしたものの、Nikitaから「新しい関数にしてくれ」と言われてget_debug_typeを作ったようです。
まあ、これまでobjectとしか言わなかったgettypeがいきなり色々な型を喋り出したら困るところも出そうですからね。

ということで、今後は型の取得はget_debug_typeに一本化できそうです。

手間を省くための定型処理を言語機能に取り込むことは、他の言語でも多々起きていることです。
たとえばJavaScriptのasync/awaitPromiseの糖衣にすぎず、async/awaitができることは全てPromiseでもできるので、究極的にはasync/awaitは不要です。
しかし非同期処理を楽に書けるようにするために言語仕様に取り込まれました。
糖衣構文の取り込み自体は、このようにさほど珍しいことでもありません。

しかし、str_containsとかis_countableとか、他言語であれば「自分で書け」と言われそうな極端に簡単な構文まで言語仕様に取り込んでしまう言語は、PHP以外にはそうそう無いのいではないかと思います。

【PHP8.0】throw文がthrow式になる

throw expressionというRFCが投票中です。

最初のアイデアは2019/12/06のSebastiaan Andewegによるツイート

それに対して2020/03/19にCarusoが反応し、そしてその日のうちにiluuu1994が最初のプルリクを出しました
はえーよ。

throw expression

Introduction

PHPのthrowは文であるため、アロー関数や三項演算子、NULL合体演算子などの式しか許されない場所から例外を投げることができません。
このRFCでは、それらを可能にするためthrow文を式に変更することを提案します。

Proposal

式を記述可能なあらゆるコンテキストでthrowが利用可能になります。
以下は思いついた便利そうな例です。

// アロー関数$callable=fn()=>thrownewException();// nullチェック$value=$nullableValue??thrownewInvalidArgumentException();// trueっぽいチェック$value=$falsableValue?:thrownewInvalidArgumentException();// 空ではない配列チェック$value=!empty($array)?reset($array):thrownewInvalidArgumentException();

他にも、議論の余地のある使用方法があります。
このRFCでは、以下のような記述も許可されています。

// ifを使った方が意図が明確になる$condition&&thrownewException();$condition||thrownewException();$conditionandthrownewException();$conditionorthrownewException();

Operator precedence

throwが式になると、優先順位を決める必要があります。
以下は現時点で有効な書式の例です。

throw$this->createNotFoundException();// こうなるthrow($this->createNotFoundException());// こうではない(throw$this)->createNotFoundException();throwstatic::createNotFoundException();// こうなるthrow(static::createNotFoundException());// こうではない(throwstatic)::createNotFoundException();throw$userIsAuthorized?newForbiddenException():newUnauthorizedException();// こうなるthrow($userIsAuthorized?newForbiddenException():newUnauthorizedException());// こうではない(throw$userIsAuthorized)?newForbiddenException():newUnauthorizedException();throw$maybeNullException??newException();// こうなるthrow($maybeNullException??newException());// こうではない(throw$maybeNullException)??newException();throw$exception=newException();// こうなるthrow($exception=newException());// こうではない(throw$exception)=newException();throw$exception??=newException();// こうなるthrow($exception??=newException());// こうではない(throw$exception)??=newException();throw$condition1&&$condition2?newException1():newException2();// こうなるthrow($condition1&&$condition2?newException1():newException2());// こうではない(throw$condition1)&&$condition2?newException1():newException2();

共通して言えるのは、全てがthrowキーワードより高い優先順位を持つということです。
このため、このRFCではthrowキーワードの優先順位を可能な限り低くすることを提案します。
現在有効なコードは、たとえ直感に反する動作だったとしても、今後も同じ動作をし続けます。
なぜなら、一般的にthrowは最後に使用するべき演算子であり、それ以降に記述した式は評価されないからです。

低い優先順位の唯一の欠点は、短絡評価のために括弧が必須になることです。

$condition||thrownewException('$condition must be truthy')&&$condition2||thrownewException('$condition2 must be truthy');// こうなる$condition||(thrownewException('$condition must be truthy')&&$condition2||(thrownewException('$condition2 must be truthy')));// こうではない$condition||(thrownewException('$condition must be truthy'))&&$condition2||(thrownewException('$condition2 must be truthy'));

もっとも、こんなコードはほぼ使われていないでしょう。

Backward Incompatible Changes

後方互換性のない変更はありません。

Other languages

C#では同じ文法が2017年に実装されました。

このような言語は他にはあまりありません。
ECMAScriptにプロポーザルがありますが、これは同じ問題を抱えているからです。

Proposed PHP Version(s)

PHP8。

投票

投票は2020/04/19まで、2/3の賛成で受理されます。
2020/04/06時点では賛成14、反対1で、受理される見込みです。

過去のML

9年前とか15年前にも同じ発想があったようですが、そのときは立ち消えになりました。
当時とはPHPのおかれた環境やRFCの出し方などがだいぶ異なることと、そしてなにより実物のプルリクがあるというのは大きいでしょう。

感想

ややこしいよね文と式。
全てが式になればいいのに。

というわけで、今後はもっと気軽にthrowすることができるようになります。
それどころかアロー関数で引数によって値を返したり例外Aを出したり例外Bを出したりすることもできちゃいますよ。
まあ正直、throwを出すようなややこしい式をアロー関数に書くんじゃないよと思ったりはするわけですが。

【PHP8.0?】PHPに名前付き引数が実装されるかもしれない

PHPのソースを眺めていたら、先日2020/04/07にNikitaがなんか面白そうなプルリクを出していました。
Named Parametersという2013年に提出されたまま忘れ去られたRFCがあるのですが、その機能を実装したものです。

どういう機能ってこういうのです。

functionhoge($foo,$bar){echo"foo=$foo,  bar=$bar";}hoge(bar=1,foo=2);// foo=2, bar=1

PythonCSharpなんかで実装されてるやつですね。

Nikita本人は機能が幾つも不足しているよと言っているのですが、不足の内容はOpcache対応や引数アンパックといった周辺機能で、基本的な機能は既に実装されているみたいです。

PHP RFC: Named Parameters

State of this RFC

これは名前付き引数についての準備的なRFCです。
このRFCの目的は、次のPHPバージョンで名前付き引数をサポートすべきか、またサポートするときはどのように実装すべきかを確認することです。
ここで解説している構文や動作は最終的なものではなく、詳細を詰めていく必要があります。

このRFCの実装はまだ完全なものではありません。
これは非常に複雑な機能なので、この機能が必要でなかったのに時間をかけて実装したくはありません。

Update 22-05-2014

私は他のことで忙しく、このRFCには取り組めていません。
このRFCはPHP6に間に合うように復活させるつもりです。
それまでの間、未解決の問題に対する議論の結果の一部をここにまとめておきます。

・名前付き引数のコンセンサスはまだ得られていません。
・名前付き引数のアンパックと、名前のない引数のアンパックは...構文に統合されます。アンパックのRFCは既に決定しているため、ここについて選択肢はあまりありません。
・継承時のパラメータ名チェックは強制されません。これはあまりにも大きなBC breakになるとはんだんされました。

主な未解決の実装上の問題は"Patch"セクションにリストアップされています。

What are named arguments?

名前付き引数とは、パラメータの順番ではなくパラメータ名を使って関数に引数を渡す方法です。

// 通常の引数array_fill(0,100,42);// 名前付き引数array_fill(start_index=>0,num=>100,value=>42);

名前付き引数に渡す引数の順番は自由です。
上記例では関数シグネチャと同じ順番で引数を渡していましたが、異なる順番で渡すこともできます。

array_fill(value=>42,num=>100,start_index=>0);

名前付き引数と名前のない引数を組み合わせることも可能であり、オプション引数の一部のみを名前付き引数で渡すことも可能になります。

htmlspecialchars($string,double_encode=>false);// ↓と同じhtmlspecialchars($string,ENT_COMPAT|ENT_HTML401,'UTF-8',false);

What are the benefits of named arguments?

名前付き引数の明白な利点の一つは、上のコードサンプルを見ればわかります。
変更したい引数までの間にある引数に対して、それぞれデフォルト値を指定する必要から解放されます。
名前付き引数があれば、変更したい引数だけを直接指定することができます。

これはデフォルト引数のRFCでも可能ですが、名前付き引数を使えば意図がより明白になります。
構文を比較してみてください。

htmlspecialchars($string,default,default,false);// vshtmlspecialchars($string,double_encode=>false);

ひとつめのコードを見ても、たまたまhtmlspecialcharsの引数を丸暗記していないかぎりfalseが何を意味するのかは分からないでしょう。

コードの自己文書化の利点は、オプション引数をスキップしないときにおいても明らかです。

$str->contains("foo",true);// vs$str->contains("foo",caseInsensitive=>true);

名前付き引数を使うことで、新しい方法で関数を使うことができるようにbなります。
引数を順番に並んだリストとしてだけではなく、キーと値のペアのリストとしても扱えるということです。
以下のような使い方が考えられます。

// 現在の構文$db->query('SELECT * from users where firstName = ? AND lastName = ? AND age > ?',$firstName,$lastName,$minAge);// 名前付き引数$db->query('SELECT * from users where firstName = :firstName AND lastName = :lastName AND age > :minAge',firstName=>$firstName,lastName=>$lastName,minAge=>$minAge);

Implementation

Internally

名前付き引数は、他の引数と同じくVM stackを通して渡されます。
これらの引数の違いは、位置引数は常にスタックの先頭に渡されるのに対し、名前付き引数は任意の順番でスタックに挿入することができるということです。
使用されないスタックの位置にはNULLが入り、引数カウントはNULLも数えます。

Errors

位置引数と名前付き引数を混在させることが可能ですが、名前付き引数は位置引数の後に配置しなければなりません。
そうしなければコンパイルエラーが発生します。

strpos(haystack=>"foobar","bar");// Fatal error: Cannot pass positional arguments after named arguments

可変長引数ではない関数に存在しない引数名を渡した場合、致命的エラーが発生します。

strpos(hasytack=>"foobar",needle=>"bar");// Fatal error: Unknown named argument $hasytack

同じ名前の引数を複数回渡した場合、新しい方で古い方が上書きされ、警告が発生します。

functiontest($a,$b){var_dump($a,$b);}test(1,1,a=>2);// 2, 1// Warning: Overwriting already passed parameter 1 ($a)test(a=>1,b=>1,a=>2);// 2, 1// Warning: Overwriting already passed parameter 1 ($a)

Collecting unknown named arguments

可変長引数の...$args構文を使った場合、余った名前付き引数は$argsに集められます。
名前付き引数は常に位置引数より後ろとなり、渡された順番が保持されます。

functiontest(...$args){var_dump($args);}test(1,2,3,a=>'a',b=>'b');// [1, 2, 3, "a" => "a", "b" => "b"]

使用例としては前述の$db->query()があります。

これはPythonで**kwargsと呼ばれている機能です。

Unpacking named arguments

引数アンパックのRFCは名前付き引数のアンパックにも対応します。

$params=['needle'=>'bar','haystack'=>'barfoobar','offset'=>3];strpos(...$params);// int(6)

文字列キーを持つ任意の値は、名前付きパラメータとして展開されます。
それ以外のキーは通常の位置引数として扱われます。

位置引数と名前付き引数をひとつの配列にまとめることも可能ですが、その場合でも引数の順番は守らなければなりません。
名前付き引数より後に位置引数が出てきた場合は警告がスローされ、アンパックは中止されます。

func_* and call_user_func_array

名前付き引数を使って、スタックから引数としてNULLが渡ってきた場合、func_*関数の挙動は以下のようになります。

func_num_args()はNULLを含んだ引数の個数を返す。
func_get_arg($n)はデフォルト値を返す。デフォルト値がない場合はNULL。
func_get_args()はデフォルト値を返す。デフォルト値がない場合はNULL。

3関数とも、未定義の引数名は無視します。
func_get_argsは値を返さず、func_num_argsはカウントに含めません。

call_user_func_arrayは名前付き引数をサポートしません。
文字列キーを持つ配列を渡すコードが壊れるからです。

Open questions

Syntax

現在の実装および提案では、名前付き引数について以下2種類の構文をサポートしています。

test(foo=>"oof",bar=>"rab");test("foo"=>"oof","bar"=>"rab");

ふたつめの構文は、引数名が予約語である場合のためにサポートされています。

test(array=>[1,2,3]);// syntax errortest("array"=>[1,2,3]);// works

この構文の選択は恣意的なもので、特に深く考えずに採用しました。
以下に、いくつか代替構文の提案があります(ほとんどはPhil Sturgeonによる提案です)。

// currently implemented:test(foo=>"oof",bar=>"rab");test("foo"=>"oof","bar"=>"rab");// キーワードを使えるtest($foo=>"oof",$bar=>"rab");test(:foo=>"oof",:bar=>"rab");test($foo:"oof",$bar:"rab");// キーワードを使えないtest(foo="oof",bar="rab");test(foo:"oof",bar:"rab");// 既に有効なコードなので不可test($foo="oof",$bar="rab");

どの構文で決定するかは議論次第です。

Collection of unknown named args into ...$opts

現在のRFCでは、位置引数と名前付き引数の両方がまとめて可変長引数の...$optsに入ってきます。
Pythonでは前者を*argsに、後者を**kwargsに入れるというアプローチをとっています。

Pros:PHPでは、Pythonではできない配列と辞書の混在ができます。
Cons:位置引数と名前付き引数を別にすることで、意図がより明確になります。必ずしも両方の引数をサポートしたいとはかぎらず、片方だけを強制したいかもしれません。

どのように扱うのが適切か、意見や議論を歓迎します。

Unpacking named args

引数アンパックについても同じ疑問が出てきます。
...$fooは位置引数と名前付き引数を一緒にできますが、*$foo**$fooに分けるべきでしょうか。

この決定は、可変長引数と同じに揃えるべきでしょう。

Signature validation allows changing parameter names

現在のところ、引数名はシグネチャに含まれていません。
位置引数しか使わない場合、これは合理的です。
引数名は関数の呼び出しに関係ないからです。

名前付き引数はこの動作を変更します。
継承先クラスが引数名を変更した場合、名前付き引数を使った呼び出しは失敗し、LSPに違反します。

interfaceA{publicfunctiontest($foo,$bar);}classBimplementsA{publicfunctiontest($a,$b){}}$obj=newB;// Pass params according to A::test() contract$obj->test(foo=>"foo",bar=>"bar");// ERROR!

名前付き引数が導入された場合、シグネチャの検証において引数名の変更にエラーを出さなければなりません。
通常の場合、インターフェイスと実装クラスの不一致は致命的エラーを発生させますが、名前付き引数において致命的エラーを出すとBC breakが大きくなりすぎてしまいます。
かわりに、より低いエラータイプ(WARNING / NOTICE / STRICT)を出すことを検討します。

これに関する具体的な議論のポイントをひとつ挙げておきます。
PHPは、実行時の動作を変更するini設定を導入する習慣を過去に置いてきました。
従って、この挙動をiniで制御できるようにすることは、私の選択肢にはありません。

Patch

差分がこちらにありますが、このパッチは不完全で、ダーティで、既知のバグがあります。

やるべき作業はまだまだ残っています。

・"Open questions"の結果を実装する。
・内部関数の全てのarginfosをドキュメントと一致するように更新する。現在のarginfo構造体は絶望的に時代遅れで、引数割り当てなどは自動的にできるようにしたい。
・内部関数において引数がスキップされたときに適切に動作するようにする。ほとんどの場合は自動的に動作するはずだが、手動調整が必要になる関数もかなりあるだろう。

感想

2014年とかPHP6とか出てくることからわかるように、このRFCはだいぶ昔に書かれてそのまんまです。
当時作成されたパッチはもはや使い物にならないため、新たにプルリクを作ってきたようです。
パッチにしろその他の内容にしろ、当時のPHPと今のPHPはだいぶ異なったものになっているので、なんにしろRFCのリファインは必要になるでしょう。

このプルリクについても、とりあえず提出されただけで何の展開もありませんし、メーリングリストでの議論も特に進んでいるわけではありません。
従って、このプルリクも今後どうなるかはわからず、再びこのまま忘れ去られるかもしれません。
しかしNikitaのことですから、いきなり完動品のプルリクが送られてきて第一線に躍り出る、なんてことがあっても驚きはないですね。

混沌の時代に実装された関数などでは特に、同じ内容の関数でも引数の順番が異なったりしていて大変なのですが、この機能が実装されたら、そのあたりを楽に処理できるようになります。
また却下されたデフォルト引数のRFCも、この名前付き引数があれば不要になります。
絶対にないといけないというほどでもないですが、存在すれば純粋に便利になる、そんな良い機能だと思います。

あとここからは完全に妄想ですが、このプルリクはジェネリクスへの足掛かりなのではないかと感じています。
Nikitaはどうもジェネリクス大好きっ子みたいですから、このプルリクを元に引数まわりに手を付けて、ついでにジェネリクスまでできるようにちゃったぜみたいなことを考えているのではないでしょうか。

RFC8774 "The Quantum Bug" 翻訳

はじめに

2020年のJoke RFCの一つ、 RFC8774 "The Quantum Bug"の翻訳です。英語は苦手なので DeepLGoogle翻訳を使用し、さらに感覚で修正しています。
正確性は保証していません。

対象読者

Joke RFCに興味がある人。

Joke RFC

Joke RFC は、RFC の中でも4月1日にエイプリルフール・ジョークとして公開されるもので、次のような特徴があります。

  • ふざけた内容をまじめに議論している(ように見せかけている)
  • インターネット技術や関連技術などの元ネタを知っていると笑える
  • RFC文書の記述形式を知っていると笑える
  • RFC になじみがないとおもしろさが半減する

一言で言えばマニアック。だが、それがいい。

Joke RFC の探し方

  1. IETFのRFCのサイトに行きます。
  2. RFC Index を開きます。TXT版の一覧がお勧めです。
  3. "1 April" (4月1日固定)で検索します。
  4. Status: が INFORMATIONAL または UNKNOWN であれば、"Joke RFC である可能性が高い" です。あとはタイトルや中身を見て判断します。

ちなみにこのRFC8774から参照しているRFC6921もJoke RFCです。

RFC 8774 "The Quantum Bug" 翻訳

Independent Submission                                          M. Welzl
Request for Comments: 8774                            University of Oslo
Category: Informational                                     1 April 2020
ISSN: 2070-1721

                        The Quantum Bug

量子バグ

Abstract

The age of quantum networking is upon us, and with it comes
"entanglement": a procedure in which a state (i.e., a bit) can be
transferred instantly, with no measurable delay between peers.  This
will lead to a perceived round-trip time of zero seconds on some
Internet paths, a capability which was not predicted and so not
included as a possibility in many protocol specifications.  Worse
than the millennium bug, this unexpected value is bound to cause
serious Internet failures unless the specifications are fixed in
time.

概要

量子ネットワークの時代がやってくると、"もつれ"を使って(ビットの)状態を遅延ゼロで瞬時に転送できるようになる。これはインターネットパス(経路)のラウンドトリップタイム(RTT)がゼロになることを意味するが、それは想定外の能力であり、多くのプロトコル仕様はそのような場合を想定していない。さらにミレニアムバグ(2000年問題)よりもたちが悪いことに、プロトコル仕様が修正されなければ、この予期せぬ動きは深刻なインターネット障害を引き起こす。

Status of This Memo

   This document is not an Internet Standards Track specification; it is
   published for informational purposes.

   This is a contribution to the RFC Series, independently of any other
   RFC stream.  The RFC Editor has chosen to publish this document at
   its discretion and makes no statement about its value for
   implementation or deployment.  Documents approved for publication by
   the RFC Editor are not candidates for any level of Internet Standard;
   see Section 2 of RFC 7841.

   Information about the current status of this document, any errata,
   and how to provide feedback on it may be obtained at
   https://www.rfc-editor.org/info/rfc8774.

(この文書はインターネット標準仕様策定のためのものではなく、あくまで情報提供のためのものである、という INFORMATIONAL 文書でお約束の説明)

Copyright Notice

   Copyright (c) 2020 IETF Trust and the persons identified as the
   document authors.  All rights reserved.

   This document is subject to BCP 78 and the IETF Trust's Legal
   Provisions Relating to IETF Documents
   (https://trustee.ietf.org/license-info) in effect on the date of
   publication of this document.  Please review these documents
   carefully, as they describe your rights and restrictions with respect
   to this document.

(コピーライトについて)

Table of Contents

   1.  Introduction
   2.  Protocols and Protocol Mechanisms That Will Fail
     2.1.  LEDBAT
     2.2.  Multipath TCP (MPTCP)
     2.3.  RTP Circuit Breakers
   3.  What can be done?
   4.  Conclusion
   5.  IANA Considerations
   6.  Security Considerations
   7.  References
     7.1.  Normative References
     7.2.  Informative References
   Author's Address

(目次)

1.  Introduction

   [RFC6921] discusses faster-than-light communication, where packets
   arrive before they are sent.  While it is amusing to entertain the
   possibility of time travel, we have to accept the cold facts: time
   travel will never work (or it would already have been used).  Quantum
   networking, however, is an entirely different matter -- commercial
   products are already available, and quantum networks will without a
   doubt become the prevalent Internet link-layer technology across the
   globe within the next five to ten years.

1.はじめに

[RFC6921]は超光速通信、つまりパケットが送信される前に到着する場合について述べている。タイムトラベルの可能性を想像するのは楽しいが、私たちは冷たい事実を受け入れなければならない: タイムトラベルはうまくいかない (今後タイムトラベルが実現するのであれば、今は既にタイムトラベルを使っているはずだ)。しかし、量子ネットワークは全く別の問題だ。量子ネットワークは商用製品が既に利用できるし、間違いなく今後5年から10年以内に世界中でインターネットのリンク層技術として普及するだろう。

   With the help of entanglement, implemented in quantum repeaters,
   quantum networks can transfer information faster than ever before: a
   state can be transmitted over a long distance instantly, with no
   delay.  This is so cool that it is also called (and, by some,
   mistaken for) teleportation.  If a path between a sender and a
   receiver is fully quantum-ized, the measured one-way delay (OWD) will
   be zero.  What's more, assuming that there are blazing fast quantum
   computers involved on both ends, the processing time will be well
   below anything measurable; hence, even the round-trip time (RTT) will
   be zero in these scenarios.

量子リピータに実装された "もつれ" を使うため、量子ネットワークはこれまで以上に速く情報を転送することができる: つまり、遅延なしに長距離で瞬時に状態を送信することができる。これはとてもクールなので、(一部では誤解されているが)テレポーテーションとも呼ばれる。送信者と受信者の間のパスが完全に量子化されている場合、一方向遅延(one-way delay, OWD)の測定値はゼロになる。さらに、パスの両端に超高速量子コンピュータがあると仮定すると、処理時間は計測不可能なほど短くなり、これらのシナリオでは、ラウンドトリップタイム(round-trip time, RTT)さえもゼロになる。

   In today's Internet, only very few protocols are prepared for such
   "0-RTT" situations (e.g., TCP with "TCP Fast Open" (TFO) [RFC7413],
   TLS 1.3 [RFC8446], and QUIC [QUIC-TRANS]).  Many others will fail in
   interesting ways; we coin the term "Quantum Bug" for such failures.
   In the following section, we will discuss some examples of Quantum
   Bugs.

今日のインターネットでは、このような "ゼロ-RTT" の状況に対応するプロトコルは非常に限られている (例えば TCP with "TCP Fast Open" (TFO) [RFC7413], TLS 1.3 [RFC8446], QUIC [QUIC-TRANS])。他の多くのプロトコルでは興味深い理由で失敗が起きる; 私たちはこのような失敗を "量子バグ" と呼んでいる。以下の節では量子バグの例をいくつか説明する。

2.  Protocols and Protocol Mechanisms That Will Fail

   The number of protocols and protocol mechanisms that will fail in the
   face of a zero RTT is too large to report here; we are truly heading
   towards something close to an Internet meltdown.  We can only provide
   some guidance to those who hunt for the Quantum Bug, by discussing
   examples of specification mistakes that will need to be fixed.

2.失敗するプロトコルおよびそのプロトコル機構について

ゼロ-RTTで失敗するプロトコルやプロトコル機構は、数が多すぎてここでは報告できない; まさにインターネットメルトダウンに向かっているのだ。私たちには、修正すべき仕様の不具合の例を議論することで量子バグの狩人へのガイドを提供することしかできない。

2.1.  LEDBAT

   The Low Extra Delay Background Transfer (LEDBAT) congestion control
   mechanism [RFC6817] is a very interesting failure case: designed to
   "get out of the way" of other traffic; it will end up sending as fast
   as possible.  Specifically, when the algorithm described in
   Section 2.4.2 of [RFC6817] obtains a delay sample, it updates a list
   of base delays that will all become 0 and current delays that will
   also all become 0.  It calculates a queuing delay as the difference
   between the current delay and the base delay (resulting in 0) and
   keeps increasing the Congestion Window (cwnd) until the queuing delay
   reaches a predefined parameter value TARGET (100 milliseconds or
   less).

2.1.LEDBAT

低外部遅延バックグラウンド・トランスポート(Low Extra Delay Background Transfer, LEDBAT) 輻輳制御機構 [RFC6817] は非常に興味深い失敗例だ。LEDBAT は他の通信の「邪魔にならない」よう設計されており、送信をできるだけ最速にする。具体的には、[RFC6817]の2.4.2節のアルゴリズムで遅延サンプルを取得する場合、全てがゼロになる基準遅延のリストと、同じく全てがゼロになる現在遅延のリストを更新する。そしてキューイング遅延として現在遅延と基準遅延の差を計算し(結果はゼロ)、キューイング遅延が事前に定義されたパラメータ TARGET値 (100 ミリ秒以下) に達するまで 輻輳帯域 (Congestion Window, cwnd) を増加させ続ける。

   A TARGET value of 100 milliseconds will never be reached, because the
   queuing delay does not grow when the sender increases its cwnd; this
   means that LEDBAT would endlessly increase its cwnd, limited only by
   the number of bits that are used to represent cwnd.  However, given
   that TARGET=0 is also allowed, this parameter choice may seem to be a
   way out.  Always staying at the target means that the sender would
   maintain its initial cwnd, which should be set to 2.  This may seem
   like a small number, but remember that cwnd is the number of bytes
   that can be transmitted per RTT (which is 0).  Thus, irrespective of
   the TARGET value, the sender will send data as fast as it can.

送信者が cwnd を増加させてもキューイング遅延は増加しないため、TARGET値が100ミリ秒に達することはない。これは LEDBAT が無限に cwnd を増加させることを意味する; ただし cwnd の表現ビット数が制限となる。しかしTARGET値にはゼロを指定できるので、上記は回避可能に思える。キューイング遅延が常にTARGET値と等しいということは、送信者が最初のcwndを維持することを意味し、そのcwndは2に設定すべきだ。この数値は小さく思えるかもしれないが、cwndはRTT(= 0)あたりに送信できるバイト数であることを思い出してほしい。つまり、TARGET値に関係なく、送信者はできるだけ早くデータを送信するということだ。

2.2.  Multipath TCP (MPTCP)

   The coupled congestion control mechanism proposed for MPTCP in
   [RFC6356] requires calculating a value called "alpha".  Equation 2 in
   [RFC6356] contains a term where a value called "cwnd_i" is divided by
   the square of the RTT, and another term where this value is divided
   by the RTT.  Enough said.

2.2.マルチパスTCP (MPTCP)

[RFC6356]でMPTCP用に提案されている結合輻輳制御機構は「アルファ」と呼ばれる値の計算が必要だ。[RFC6356]の式2には、"cwnd_i"と呼ばれるRTTの2乗で割る項と、もう一つRTTで割る項が含まれている。説明はもういいだろう。

2.3.  RTP Circuit Breakers

   The RTP Circuit Breakers [RFC8083] require calculation of a well-
   known equation which yields the throughput of a TCP connection:

2.3.RTPサーキットブレーカー

RTPサーキットブレーカー[RFC8083]は、TCP接続のスループットを算出する有名な方程式を使う:

                             s
   X = -------------------------------------------------------------
       Tr*sqrt(2*b*p/3)+(t_RTO * (3*sqrt(3*b*p/8) * p * (1+32*p*p)))

   where Tr is the RTT and t_RTO is the retransmission timeout of TCP
   (we don't need to care about the other variables).  As we will
   discuss in Section 3, t_RTO is lower-bounded with 1 second;
   therefore, it saves us from a division by zero.  However, there is
   also a simplified version of this equation:

(式は略) ここで、TrはRTT、t_RTOはTCPの再送信タイムアウトだ(今は他の変数を気にする必要はない)。3節で説明するが、t_RTOの下限は1秒だ; つまり、ゼロ除算にはならない。しかし、この式には簡略版もある。

             s
   X = ----------------
       Tr*sqrt(2*b*p/3)

   Unfortunately, [RFC8083] states: "It is RECOMMENDED that this
   simplified throughput equation be used since the reduction in
   accuracy is small, and it is much simpler to calculate than the full
   equation."  Due to this simplification, many multimedia applications
   will crash.

(式は略) 残念ながら、[RFC8083]では次のように述べている: 「精度の低下が小さく、完全な式よりも計算がはるかにシンプルなので、この簡略版スループット式を使用することが"推奨される"」。この簡略化によって、多くのマルチメディアアプリケーションがクラッシュする。

3.  What can be done?

   Fear not: when everything else fails, TCP will still work.  Its
   retransmission timeout is lower-bounded by 1 second [RFC6298].
   Moreover, while its cwnd may grow up to the maximum storable number,
   data transmission is limited by the Receiver Window (rwnd).  This
   means that flow control will save TCP from failing.

3.何ができるのか?

恐れる必要はない: 他のすべてが失敗しても、TCPは引き続き機能する。TCPの再送信タイムアウトの下限は1秒だ [RFC6298]。さらに、cwndが最大まで拡大しても、データ通信は受信帯域(Receiver Window, rwnd)で制限される。つまり、フロー制御でTCPの失敗を防ぐことができる。

   From this, we can learn two simple rules: lower-bound any values
   calculated from the RTT (and, obviously, do not divide by the RTT),
   and use flow control.  Specifications will need to be updated by
   fixing all RTT-based calculations and introducing flow control
   everywhere.  For example, UDP will have to be extended with a
   receiver window, e.g., as a UDP option [UDP-OPT].

ここから2つのシンプルなルールが得られる: RTTから計算された値はすべて下限値とし(明示的に、RTTで割らないようにする)、かつフロー制御を使用する。RTTベースの計算をすべて修正し、どこでもフロー制御ができるように仕様を更新する必要がある。例えば、UDPはUDPオプション[UDP-OPT]のように、受信帯域制御で拡張する必要がある。

4.  Conclusion

   We are in trouble, and there is only one way out: develop a
   comprehensive list of all RFCs containing "0-RTT" mistakes (taking
   [RFC2626] as a guideline), and update all code.  This needs to happen
   fast, the clock is ticking.  Luckily, if we are too slow, we will
   still be able to use TCP to access the specifications.  With DNS over
   TCP [RFC7766], name resolution to find the server containing the
   specifications should also work.

4.結論

私たちは困っており、出口は一つしかない: ([RFC2626]をガイドラインとして) ゼロ-RTT の不具合を持つすべてのRFCの包括的なリストを作成し、すべてのコードを更新することだ。時間はない。早くすべきだ。幸いなことに、私たちの対応が遅すぎた場合でも、仕様書にアクセスするのにTCPを使うことができる。DNS over TCP [RFC7766]を使えば、仕様書があるサーバを見つけるための名前解決も動作するはずだ。

5.  IANA Considerations

   This document has no IANA actions.

5.IANAでの検討

IANAでは検討されていない。

  6.  Security Considerations

   Flow control must be used on 0-RTT paths, or else an attacker can
   completely overwhelm a sender with data in a denial-of-service (DoS)
   attack within an instant.  Flow control will need to be added to
   protocols that do not currently have it, such as UDP or ICMP.  IPv6
   will not save us.

6.セキュリティに関する考慮事項

フロー制御はゼロ-RTTパスで使用する必要がある。さもないと攻撃者は瞬時にDoS攻撃のデータで送信者を完全に圧倒してしまう。フロー制御は、UDP や ICMP のような、現在は対応していないプロトコルにも追加する必要がある。IPv6は私たちを救わない。

7.  References    

7.1.  Normative References    

   [RFC2626]  Nesser II, P., "The Internet and the Millennium Problem
              (Year 2000)", RFC 2626, DOI 10.17487/RFC2626, June 1999,
              <https://www.rfc-editor.org/info/rfc2626>.    

   [RFC6921]  Hinden, R., "Design Considerations for Faster-Than-Light
              (FTL) Communication", RFC 6921, DOI 10.17487/RFC6921,
              April 2013, <https://www.rfc-editor.org/info/rfc6921>.    

7.2.  Informative References    

   [QUIC-TRANS]
              Iyengar, J. and M. Thomson, "QUIC: A UDP-Based Multiplexed
              and Secure Transport", Work in Progress, Internet-Draft,
              draft-ietf-quic-transport-27, 21 February 2020,
              <https://tools.ietf.org/html/draft-ietf-quic-transport-
              27>.    

   [RFC6298]  Paxson, V., Allman, M., Chu, J., and M. Sargent,
              "Computing TCP's Retransmission Timer", RFC 6298,
              DOI 10.17487/RFC6298, June 2011,
              <https://www.rfc-editor.org/info/rfc6298>.    

   [RFC6356]  Raiciu, C., Handley, M., and D. Wischik, "Coupled
              Congestion Control for Multipath Transport Protocols",
              RFC 6356, DOI 10.17487/RFC6356, October 2011,
              <https://www.rfc-editor.org/info/rfc6356>.    

   [RFC6817]  Shalunov, S., Hazel, G., Iyengar, J., and M. Kuehlewind,
              "Low Extra Delay Background Transport (LEDBAT)", RFC 6817,
              DOI 10.17487/RFC6817, December 2012,
              <https://www.rfc-editor.org/info/rfc6817>.    

   [RFC7413]  Cheng, Y., Chu, J., Radhakrishnan, S., and A. Jain, "TCP
              Fast Open", RFC 7413, DOI 10.17487/RFC7413, December 2014,
              <https://www.rfc-editor.org/info/rfc7413>.    

   [RFC7766]  Dickinson, J., Dickinson, S., Bellis, R., Mankin, A., and
              D. Wessels, "DNS Transport over TCP - Implementation
              Requirements", RFC 7766, DOI 10.17487/RFC7766, March 2016,
              <https://www.rfc-editor.org/info/rfc7766>.    

   [RFC8083]  Perkins, C. and V. Singh, "Multimedia Congestion Control:
              Circuit Breakers for Unicast RTP Sessions", RFC 8083,
              DOI 10.17487/RFC8083, March 2017,
              <https://www.rfc-editor.org/info/rfc8083>.    

   [RFC8446]  Rescorla, E., "The Transport Layer Security (TLS) Protocol
              Version 1.3", RFC 8446, DOI 10.17487/RFC8446, August 2018,
              <https://www.rfc-editor.org/info/rfc8446>.    

   [UDP-OPT]  Touch, J., "Transport Options for UDP", Work in Progress,
              Internet-Draft, draft-ietf-tsvwg-udp-options-08, 12
              September 2019, <https://tools.ietf.org/html/draft-ietf-
              tsvwg-udp-options-08>.    

Author's Address    

   Michael Welzl
   University of Oslo
   PO Box 1080 Blindern
   N-0316 Oslo
   Norway    

   Phone: +47 22 85 24 20
   Email: michawe@ifi.uio.no    

【PHP8.0】PHPでアトリビュート/アノテーション/デコレータが書けるようになる

Attributes v2というRFCが投票中です。
投票期間は2020/05/04まで、投票者の2/3の賛成で受理されます。
2020/04/27時点では賛成48反対1で、ほぼ間違いなく可決されます。

Attributes v2

Introduction

このRFCは、クラス/プロパティ/関数/メソッド/引数/定数の宣言に、構造化されたアトリビュートをメタデータとして記述できるようにする提案です。
アトリビュートは、コードの宣言に直接設定ディレクティブを埋め込むことで定義されます。

同じような概念としてJavaのAnnotation、C#/C++/Rust/HackにおけるAttribute、Python/JavascriptにおけるDecoratorが存在します。

これまで、PHPではこのようなメタデータとしては非構造的であるdoc-commentsしか存在しませんでした。
しかしdoc-commentsはただの文字列であり、言語によって解釈されることはありません。
構造化された情報を保持するために、PHPの様々なコミュニティにおいて@ベースの疑似メタデータが考案されてきました。

ユーザランドでの使用例に加え、拡張機能などではコンパイルや構文解析、コード生成、実行時の挙動に影響を与えるようなアトリビュートの使用例も多く存在します。
下のほうに例を示します。

ユーザランドのdoc-commentsが多く使われていることから、この機能がコミュニティから強く求められていることがわかります。

Proposal

Attribute Syntax

アトリビュートは、既存の構文トークンT_SLT_SR、すなわち<<>>を使った特別なフォーマットのテキストです。

アトリビュートは言語内の多くの対象に適用されます。
・関数 (クロージャやアロー関数含む)
・クラス (無名クラス含む)、インターフェイス、トレイト
・クラス定数
・プロパティ
・メソッド
・関数/メソッド引数

以下は例です。

<<ExampleAttribute>>classFoo{<<ExampleAttribute>>publicconstFOO='foo';<<ExampleAttribute>>public$x;<<ExampleAttribute>>publicfunctionfoo(<<ExampleAttribute>>$bar){}}$object=new<<ExampleAttribute>>class(){};<<ExampleAttribute>>functionf1(){}$f2=<<ExampleAttribute>>function(){};$f3=<<ExampleAttribute>>fn()=>1;

アトリビュートはdoc-blockコメントと同様に、それが属する宣言の直前に記載します。
doc-blockコメントとどちらが先かといえば、コメントの前にも後ろにも書くことができます。

<<ExampleAttribute>>/** docblock */<<AnotherExampleAttribute>>functionfoo(){}

関数、クラス、メソッド、プロパティ、パラメータはひとつ以上のアトリビュートを持つことができます。

<<WithoutArgument>><<SingleArgument(0)>><<FewArguments('Hello','World')>>functionfoo(){}

ひとつの対象に同じアトリビュート名を複数回指定することが可能です。

アトリビュートは1行で複数回宣言できます。

<<WithoutArgument>><<SingleArgument(0)>><<FewArguments('Hello','World')>>functionfoo(){}

<<>>は式の接頭辞として使用されており、他言語で使用されているジェネリクスの一般的な構文<T>がもし今後導入されることになったとしても、それがアトリビュート構文と衝突することはありません。

構文についてはこのRFCで最も議論されてきたポイントであり、@:として表される新たな構文トークンT_ATTRIBUTEを導入する代替案も考えられました。
構文の選択はRFCの二次投票となります。

@:WithoutArgument@:SingleArgument(0)@:FewArguments('Hello','World')functionfoo(){}

この構文は、doc-blockコメントで一般的に見られる@を使用します。
欠点としては、空白を許可するとアトリビュートの終端を判別できなくなってしまうので、空白を禁止しなければならないことです。

最も要望されるであろう@[]が使えない理由については、下にあるAlternative Syntaxの議論を参照してください。

Attribute Names Resolve to Classes

アトリビュートは、コンパイル中にその時点でインポートされている全てのシンボルについて解決されます。
これはアトリビュートに名前空間を許容するためであり、別のライブラリやアプリケーションで同じアトリビュートが誤って再利用されるのを避けるためです。

useMy\Attributes\SingleArgument;useMy\Attributes\Another;<<SingleArgument("Hello")>><<Another\SingleArgument("World")>><<\My\Attributes\FewArguments("foo","bar")>>functionfoo(){}

このことはクラスにアトリビュートを宣言する際にも利点があります。
・リフレクションが解析しやすい。後述。
・静的解析ツールによる検証が容易になる。
・IDEがオートコンプリートや引数に対応することができる。

クラスアトリビュートを指定する例は以下のようになります。

namespaceMy\Attributes;usePhpAttribute;<<PhpAttribute>>classSingleArgument{public$value;publicfunction__construct(string$value){$this->value=$value;}}

Compiler and Userland Attributes

このRFCは、2種類のアトリビュートを区別しています。
・コンパイラアトリビュート:コンパイル時に検証される
・ユーザランドアトリビュート:リフレクションで検証される

コンパイラアトリビュートは、PhpCompilerAttributeに属する内部クラスです。

ユーザランドアトリビュートは、PhpAttributeに属するユーザランドのクラスです。

コンパイル時にコンパイラアトリビュートが見つかると、実行エンジンはアトリビュートに紐付けられているバリデーションのコールバックを呼び出します。
たとえばこのパッチにはPhpCompilerAttributeのバリデーションコールバックが含まれており、ユーザがPhpCompilerAttributeを使うのを防いでいます。

#include "zend_attributes.h"
voidzend_attribute_validate_phpcompilerattribute(zval*attribute,inttarget){if(target!=ZEND_ATTRIBUTE_TARGET_CLASS){zend_error(E_COMPILE_ERROR,"The PhpCompilerAttribute can only be used on class declarations and only on internal classes");}else{zend_error(E_COMPILE_ERROR,"The PhpCompilerAttribute can only be used by internal classes, use PhpAttribute instead");}}INIT_CLASS_ENTRY(ce,"PhpCompilerAttribute",NULL);zend_ce_php_compiler_attribute=zend_register_internal_class(&ce);zend_compiler_attribute_register(zend_ce_php_compiler_attribute,zend_attribute_validate_phpcompilerattribute);

引数zvalは渡された全ての引数を含み、targetはアトリビュートが正しく宣言されているかを検証する為の定数です。
ユーザランドクラスはPhpCompilerAttributeを使用することができません。
使おうとするとエラーが発生します。

<?php<<PhpCompilerAttribute>>classMyAttribute{}// Fatal error: The PhpCompilerAttribute can only be used by internal classes, use PhpAttribute instead

アトリビュートをクラスツールにマッピングすることで、エディタやIDEは、アトリビュートの構文やコンテキスト情報を開発者に提供することができます。
この方法の欠点は、コンパイラアトリビュートがユーザランドアトリビュートであると誤って分類されてしまうことです。

Constant Expressions in Attribute Arguments

アトリビュートは定数AST式として評価されますが、これは引数を許可することを意味します。

<<SingleArgument(1+1)>><<FewArguments(PDO::class,PHP_VERSION_ID)>>

この主な使用例は、定数/クラス定数を参照することです。
定数を参照することで、既に定数として存在する情報を再定義する重複を避けることができます。
もうひとつの利点として、ツールやIDEによる静的解析でアトリビュートを検証できるということです。

定数ASTは、リフレクションを通してアクセスする際は値に解決されます。
これはかつて提出されたアトリビュートRFCとは意図的に異なる挙動です。

またパーサは、ビットシフト演算子とアトリビュート構文を区別できます。

<<BitShiftExample(4>>1,4<<1)>>functionfoo(){}

Reflection

ReflectionクラスにgetAttributes()メソッドが追加され、ReflectionAttributeインスタンスの配列を返します。

functionReflectionFunction::getAttributes(string$name=null,int$flags=0):ReflectionAttribute[];functionReflectionClass::getAttributes(string$name=null,int$flags=0):ReflectionAttribute[];functionReflectionProperty::getAttributes(string$name=null,int$flags=0):ReflectionAttribute[];functionReflectionClassConstant::getAttributes(string$name=null,int$flags=0):ReflectionAttribute[];

引数$nameがあれば指定したアトリビュート、もしくはそのサブクラスを含めたものを返します。

$attributes=$reflectionFunction->getAttributes(\My\Attributes\SingleArgument::class);

引数$flagが未指定の場合、getAttributes()メソッドは名前が完全一致したアトリビュートだけを返し、この動作がデフォルトです。
ReflectionAttribute::IS_INSTANCEOFを指定すると、instanceofを通過する全てのアトリビュートを返すようになります。

$attributes=$reflectionFunction->getAttributes(\My\Attributes\MyAbstractAttribute::class,\ReflectionAttribute::IS_INSTANCEOF);

ReflectionAttributeクラスは以下のようになります。

classReflectionAttribute{publicfunctiongetName():stringpublicfunctiongetArguments():arraypublicfunctionnewInstance():object}

アトリビュートの検証はReflectionAttribute::newInstance()でのみ行われるので、実は必ずしもアトリビュート名に対応したクラスを定義する必要はありません。
アトリビュート名と引数は直接ReflectionAttributeから取って来れます。

以下は完全な例です。

namespaceMy\Attributes{<<PhpAttribute>>classSingleArgument{public$argumentValue;publicfunction__construct($argumentValue){$this->argumentValue=$argumentValue;}}}namespace{<<SingleArgument("Hello World")>>classFoo{}$reflectionClass=new\ReflectionClass(Foo::class);$attributes=$reflectionClass->getAttributes();var_dump($attributes[0]->getName());var_dump($attributes[0]->getArguments());var_dump($attributes[0]->newInstance());}/**
string(28) "My\Attributes\SingleArgument"
array(1) {
  [0]=>
  string(11) "Hello World"
}
object(My\Attributes\SingleArgument)#1 (1) {
  ["argumentValue"]=>
  string(11) "Hello World"
}
**/

この使い方では、getAttributes()は決して例外をスローしません。
これにより、異なるライブラリが同じ名前のアトリビュートを定義していた際の問題を回避することができます。

Use Cases

Use Cases for PHP Extensions

アトリビュートの主な使用先は、PHPコアと拡張モジュールになるでしょう。

HashTablesへのアトリビュートは、全てのzend_class_entry/op_array/zend_property_info/zend_class_constantで使用可能です。

PHPコアや拡張モジュールは、ある定義にアトリビュートがあるかどうかチェックしたくなることがあるでしょう。
例としてOpcache JITに対する@jitのチェックなどです。
これは、関数やメソッドを常に最適化するようJITに指示します。

アトリビュートが実装されれば、拡張モジュールでは以下のように書けるようになります。

staticintzend_needs_manual_jit(constzend_op_array*op_array)returnop_array->attributes&&zend_hash_str_exists(op_array->attributes,"opcache\\jit",sizeof("opcache\\jit")-1));

開発者は、doc-commentのかわりにアトリビュートを使うことができます。

useOpcache\Jit;<<Jit>>functionfoo(){}

Other potential core and extensions use cases/ideas

以下はアトリビュートの使用法のアイデアです。
RFCの一部ではないことに注意してください。

関数/メソッドの非推奨。
アトリビュートを持つほぼ全ての言語にこの機能が組み込まれています。
PHPにこれがあれば、クラスやプロパティ、定数を非推奨にすることができます。

// アイデアだよ。RFCの一部ではないよusePhp\Attributes\Deprecated;<<Deprecated("Use bar() instead")>>functionfoo(){}

非推奨アトリビュートは、今のところtrigger_errorを使うことができません。

classFoo{<<Deprecated()>>constBAR='BAR';}echoFoo::BAR;// PHP Deprecated:  Constant Foo::BAR is deprecated in test.php on line 7

Reclassify Engine WarningsSupport Rewinding GeneratorsのRFCのようなレガシー動作を、オプトインで変更します。
Rustが似たような機能を持っています。

// アイデアだよ。RFCの一部ではないよusePhp\Attributes\Deny;usePhp\Attributes\Allow;<<Allow("rewind_generator")>>functionbar(){yield1;}<<Deny("undeclared_variables")>>functionfoo(){echo$foo;// PHP Fatal error:  Uncaught TypeError: Access to undeclared variable $foo}<<Deny("dynamic_properties")>>classFoo{}$foo->bar;// PHP Fatal error:  Uncaught Error: Invalid access to dynamic property Foo::$bar

Rustっぽいマクロの一部は、旧バージョンのPHPでのみPolyfillを読み込んだりするときに便利かもしれません。
ライブラリがOpcacheやpreloadingなどを条件付きで宣言するときに役立つでしょう。

// アイデアだよ。RFCの一部ではないよusePhp\Attributes\ConditionalDeclare;usePhp\Attributes\IgnoreRedeclaration;<<ConditionalDeclare(PHP_VERSION_ID<70000)>>// PHP7.0以上ならASTによって削除される<<IgnoreRedeclaration>>// 重複時はエラーを出さず単に無視するfunctionintdiv(int$numerator,int$divisor){}

最終的には、あるアトリビュートの引数を返すAPIや、全アトリビュートの一覧を返すAPIが含まれる予定です。
これによって拡張機能の作者は、最小限の労力でアトリビュートを使うことができるようになります。
以下は草案です。

/* アトリビュート名から引数一覧を返す */HashTable*zend_attribute_get(HashTable*attributes,char*name,size_tname_len);/* アトリビュートを返す */zval*zend_attribute_all(HashTable*attributes,char*name,size_tname_len);

Userland Use-Case: Declaring Event Listener Hooks on Objects

ユーザランドにおいて、アトリビュートは宣言に対する追加設定を宣言のすぐ傍に置くことができるという利点があります。
以下はSymfonyのEventSubscribersをアトリビュートを使ってリファクタリングする例です。
EventSubscriberInterfaceは、イベントをどのクラスのどのメソッドで処理するかをgetSubscribedEvents()で宣言する必要があります。

// 現在のコードclassRequestSubscriberimplementsEventSubscriberInterface{publicstaticfunctiongetSubscribedEvents():array{return[RequestEvent::class=>'onKernelRequest'];}publicfunctiononKernelRequest(RequestEvent$event){}}// リファクタした<<PhpAttribute>>classListener{public$event;publicfunction__construct(string$event){$this->event=$event;}}classRequestSubscriber{<<Listener(RequestEvent::class)>>publicfunctiononKernelRequest(RequestEvent$event){}}// アトリビュートを使ったイベントディスパッチャclassEventDispatcher{private$listeners=[];publicfunctionaddSubscriber(object$subscriber){$reflection=newReflectionObject($subscriber);foreach($reflection->getMethods()as$method){// Listenerアトリビュートを取得$attributes=$method->getAttributes(Listener::class);foreach($attributesas$listenerAttribute){/** @var $listener Listener */$listener=$listenerAttribute->newInstance();// $listener->eventはcallable$this->listeners[$listener->event][]=[$subscriber,$method->getName()];}}}publicfunctiondispatch($event,$args...){foreach($this->listeners[$event]as$listener){// 呼び出し$listener(...$args);}}}$dispatcher=newEventDispatcher();$dispatcher->addSubscriber(newRequestSubscriber());$dispatcher->dispatch(RequestEvent::class,$payload);

Userland Use-Case: Migrating Doctrine Annotations from Docblocks to Attributes

アトリビュートのRFCが考慮した主要なケースのひとつが、広く普及しているDoctrine Annotationsライブラリからの移行可能性です。

PHPコアがアトリビュートをサポートすることで、ユーザがDoctrine Annotationsからアトリビュートへ移行するための基盤を確保することができます。

このためこのRFCは、名前空間を使ったアトリビュートの操作が主な要件となっています。

Doctrineおよび任意のユーザランドライブラリは、親クラスの名前フィルタを利用して、興味のあるアトリビュートだけを抽出することができます。
提案のリフレクションAPIを使用し、独自のロジックを追加することで、より厳格なアトリビュートの使用を強制することができるようになります。

以下に、Doctrineのアノテーションと、このRFCのアトリビュートで同じことを実装した複雑なオブジェクトの例を示します。

<?phpuseDoctrine\ORM\AttributesasORM;useSymfony\Component\Validator\ConstraintsasAssert;<<ORM\Entity>>/** @ORM\Entity */classUser{/** @ORM\Id @ORM\Column(type="integer"*) @ORM\GeneratedValue */<<ORM\Id>><<ORM\Column("integer")>><<ORM\GeneratedValue>>private$id;/**
     * @ORM\Column(type="string", unique=true)
     * @Assert\Email(message="The email '{{ value }}' is not a valid email.")
     */<<ORM\Column("string",ORM\Column::UNIQUE)>><<Assert\Email(array("message"=>"The email '{{ value }}' is not a valid email."))>>private$email;/**
     * @ORM\Column(type="integer")
     * @Assert\Range(
     *      min = 120,
     *      max = 180,
     *      minMessage = "You must be at least {{ limit }}cm tall to enter",
     *      maxMessage = "You cannot be taller than {{ limit }}cm to enter"
     * )
     */<<Assert\Range(["min"=>120,"max"=>180,"minMessage"=>"You must be at least {{ limit }}cm tall to enter"])>><<ORM\Column(ORM\Column::T_INTEGER)>>protected$height;/**
     * @ORM\ManyToMany(targetEntity="Phonenumber")
     * @ORM\JoinTable(name="users_phonenumbers",
     *      joinColumns={@ORM\JoinColumn(name="user_id", referencedColumnName="id")},
     *      inverseJoinColumns={@ORM\JoinColumn(name="phonenumber_id", referencedColumnName="id", unique=true)}
     *      )
     */<<ORM\ManyToMany(Phonenumber::class)>><<ORM\JoinTable("users_phonenumbers")>><<ORM\JoinColumn("user_id","id")>><<ORM\InverseJoinColumn("phonenumber_id","id",JoinColumn::UNIQUE)>>private$phonenumbers;}

アトリビュートは名前付きパラメータをサポートしていないため、少し制限があります。
これがアトリビュートが関数呼び出しのような構文を利用している理由ですが、もし名前付きパラメータがサポートされれば、自動的にこのRFCもその恩恵を受けることになります。

ユーザランドのアトリビュートへの移行には、Rectorのようなツールが役立ちます。

Criticism and Alternative Approaches

Alternative Syntax: Why not use @ or [] like other languages?

どうして@[]ではないの?

構文として<<>>を使用する理由は、コードのこの場所でまだ使用できる数少ない構文のひとつであり、その中でも自然に見えるものだからです。
接頭辞演算子としてまだ使われていない他の記号を使うことも可能ですが、実質的に使えそうなものは'%'くらいです。
他に使える記号というのは|=/などです。

@[]は、エラー抑制演算子と配列短縮構文に競合するため使用することができません。
以下のような構文は、現在既に有効なPHPコードです。

[[@SingleArgument("Hello")]]

この構文が配列宣言かアトリビュートかを決定するためには、無制限に先のトークンを調べなければならなくなる可能性があります。

Why not extending Doc Comments?

Doc Commentsをそのまま拡張するのではだめなの?

アトリビュートはDoc Commentsより優れています。

・名前空間により、同じDoc Commentsを使用している複数のライブラリによる競合を防ぎます。
・アトリビュートの存在チェックはo(1)のハッシュキーチェックであり、strstrやDoc Commentsのパースより高性能です。
・アトリビュートをクラスにマッピングすることで、アトリビュートが正しい構文であることを保証し、Doc Commentsの書き間違いによるバグの発生を減らします。
・アノテーションは非常に多くのツールやコミュニティで一般に使われているので大きな需要があります。しかし初心者がコメントと見誤ると混乱を招くことになるでしょう。また/*/**の違いもバグの原因になります。

PHPで既存のDoc Commentsを解析して構造化することは可能かもしれませんが、Doc Commentsの方言ごとに追加のパーサを呼び出す必要があります。
Doc Commentsは正しい文法になっていない可能性があるため、文法エラーの取り扱いを決めなければなりません。
最終的に、これはPHP内部に別の言語が存在するということになりそうです。
この方法は、アトリビュートを導入するより遙かに複雑となり、望ましくありません。

Why not always map attributes to simple arrays instead for simplicity?

シンプルに、アトリビュートは常に配列にマッピングするようにすればよくない?

アトリビュートのクラス名解決が何故重要なのか、その利点を前のセクションで解説しました。
アトリビュートが正しいかどうかの検証は、文法が正しいかどうかを検証できないDoc Commentsよりも大きなメリットがあります。

Why not a stricter solution like Doctrine Annotations?

Doctrine Annotationsのようにより厳密なソリューションは導入しないの?

このRFCは、PHPの基本的なアトリビュート機能のみを提案しています。
一般的なソリューションを全て解決するためには様々なユースケースを考慮しなければなりませんが、大抵の場合はDoctrineほど細かなシステムは必要ありません。

Why are nested attributes not allowed?

アトリビュートのネストが許可されないのは何故?

アトリビュートのネストとは、あるアトリビュートを他のアトリビュートの引数として定義するということを意味します。
これは引数でアトリビュートを宣言できるということなので、意図的に禁止されています。

Naming (attributes or annotations)

この機能の"アトリビュート"という名前は、既に使われているアノテーションとの混同を避けるために付けられました。
これによってDoctrine AnnotationsはPHP7ではDoc Commentsで実装され、PHP8ではアトリビュートで実装されている、といったことがおこります。

Backward Incompatible Changes

なし。

Proposed PHP Version(s)

PHP8.0

RFC Impact

To Core

トークン、ASTノード、zend_class_entry、zend_class_constant、zend_op_array、zend_property_infoの全てにアトリビュートを追加する必要があります。

To SAPIs

なし。

To Existing Extensions

なし。

JITは@JITではなくOpcache\Jitを、@nojitのかわりにOpcache\Nojitを使うことになる予定ですが、まだ未定です。

To Opcache

パッチに含まれており、100%の互換ではない可能性があります。

New Constants

なし。

php.ini Defaults

なし。

Open Issues

なし。

Future Scope

・名前付きパラメータとの統合
・下位互換性を壊すことなく、既存関数を新しい動作で拡張させる。
・関数/メソッドが呼ばれたとき、プロパティ/定数にアクセスしたときに非推奨を通知する<<Deprecated>>
・型付きプロパティとアトリビュートで、JSON/XMLからオブジェクトへの直列化がPHPコアでできるようになる。
<<«SingleArgument("foo"), MultiArgument("bar", "baz")>>を簡単に書けるような短縮構文。

Voting

2020/04/27時点で、導入には賛成48反対1で、ほぼ導入決定です。

構文は<<>>が40人、@:が10人で、<<>>に決まると思われます。

Patches and Tests

https://github.com/beberlei/php-src/pull/2<<>>
https://github.com/kooldev/php-src/pull/2@:

References

他言語でのアトリビュート/アノテーション/デコレータ。

Rust Attributes
C# Attributes
Java Annotation
TypeScript/ECMAScript Decorators
C++ Attributes
Go Tags
Attributes in Hack

かつて却下されたり放棄されたRFC。

Attributes v1
Annotations v2
Reflection Annotations using the Doc-Comment
Simple Annotations
Annotations in DocBlock RFC
Class Metadata RFC

感想

ほぼ全員賛成というのがちょっと信じがたいんだけど。
個人的にはどちらかというと賛成ですが、正直もっと意見が割れてもよさそうな提案ですよね。

ということで、PHP8からはアトリビュートが使えるようになります。
例を見るに、AttributeInterfeceをimplementsしたりとかも不要で、普通にクラスを書いたらいきなりアトリビュート名として使えるんですかねこれ。
ちょっとユーザレベルでの使い方がいまいちよくわかりませんでした。

というか正直、全体的に意味のよくわからないところが多々ありました。
私は普段ソースまで追ってないので、いきなりAST構文木とかzend_class_entryとか言われても知らんがな!ってかんじですよ。
きっと誰かが補足してくれるはず。

あと、それでは具体的にデフォルトでどんなアトリビュートが用意されてるの、ってのもRFCには書かれていません。
複雑なアトリビュートを定義するにはどうすればいいの、というのもRFCではちょっとよくわかりません。
このあたりは今後ドキュメントの追加をおねがいしたいところですね。
まあPHPのマニュアルは親切すぎて困るくらい丁寧なので、そのうち充実してくるとは思いますが。

【PHP8.0】StartsWith/EndsWithがPHP本体に実装される

先日PHP8でstr_containsが導入されることが決まったばかりですが、さらにもっと直接的な『〇〇で始まる』『〇〇で終わる』関数までも導入されることになりました。

Add str_starts_with() and str_ends_with() functionsというRFCが投票中です。
2020/05/04時点では賛成50反対4で、ほぼ導入確定です。

PHP RFC: Add str_starts_with() and str_ends_with() functions

Introduction

str_starts_withは、文字列が指定の文字列で始まるか否かをチェックし、結果をbool値で返します。
str_ends_withは、文字列が指定の文字列で終わるか否かをチェックし、結果をbool値で返します。

これらの機能は既存の文字列関数、たとえばsubstrstrpos/strrpos、そしてstrncmpsubstr_compare、あまつさえstrlenなどを駆使して実装されてきました。
これらユーザランドの実装には、様々な問題点があります。

str_starts_withとstr_ends_withの需要は高く、SymfonyLaravelYiiFuelPHP、そしてPhalconと、あらゆるフレームワークによってサポートされています。

文字列の始めと終わりをチェックすることは非常に一般的なタスクであり、簡単に行えるべきです。
多くのフレームワークがこのタスクを実装しているということは、このタスクを実行することが簡単ではないことを意味しています。
JavaScript/Java/Haskell/Matlabといった多くの高水準言語が標準でこの機能を実装している理由でもあります。
文字列の開始と終了をチェックすることは、これだけのためにフレームワークを導入したり、ユーザランドで最適ではない(どころかバグが入るかもしれない)実装を行ったりする必要のあるべき作業ではありません。

Downsides of Common Userland Approaches

この機能のアドホックな実装は、専用関数に比べると直感的ではありません。
PHPのニュービーや、他言語と同時開発する開発者にとっては特にそうです。
また、特に===を含む場合、実装を簡単に間違えます。
さらに多くのユーザランド実装はパフォーマンス上の問題があります。

注意:以下の実装には、E_WARNINGを防ぐために$needle === "" ||strlen($needle) <= strlen($haystack) &&のようなガードを入れましょう。

str_starts_with

substr($haystack,0,strlen($needle))===$needle

$haystackの無駄なコピーが発生するため、メモリ効率が良くありません。

strpos($haystack,$needle)===0

$needleが見つからなかった場合に$haystackを最後まで調べてしまうため、CPU効率が悪くなります。

strncmp($haystack,$needle,strlen($needle))===0// genericstrncmp($subject,"prefix",6)===0// ad hoc

これは効率的ですが、$needleの文字数を別に渡す必要があり冗長です。

str_ends_with

substr($haystack,-strlen($needle))===$needle

str_starts_with同様、メモリ効率がよくありません。

strpos(strrev($haystack),strrev($needle))===0

str_starts_with同様CPU効率が悪いだけでなく、文字列反転処理まで入るので、さらに非効率です。

strrpos($haystack,$needle)===strlen($haystack)-strlen($needle)

冗長であり、CPURL効率が悪くなることがあります。

substr_compare($haystack,$needle,-strlen($needle))===0// genericsubstr_compare($subject,"suffix",-6)===0// ad hoc

効率的ですが、冗長です。

Proposal

2つの関数、str_starts_with()str_ends_with()を導入します。

str_starts_with(string$haystack,string$needle):boolstr_ends_with(string$haystack,string$needle):bool

str_starts_with()は、$haystack$needleで始まるかどうかを調べます。
strlen($needle) > strlen($haystack)であれば即座にfalseを返し、そうでなければ両文字列を比較し、先頭一致すればtrueを、一致しなければfalseを返します。

str_ends_with()も同じですが、後方一致です。

以下に例を示します。

$str="beginningMiddleEnd";if(str_starts_with($str,"beg"))echo"printed\n";// trueif(str_starts_with($str,"Beg"))echo"not printed\n";// falseif(str_ends_with($str,"End"))echo"printed\n";// trueif(str_ends_with($str,"end"))echo"not printed\n";// false// 空文字if(str_starts_with("a",""))echo"printed\n";// trueif(str_starts_with("",""))echo"printed\n";// trueif(str_starts_with("","a"))echo"not printed\n";// falseif(str_ends_with("a",""))echo"printed\n";// trueif(str_ends_with("",""))echo"printed\n";// trueif(str_ends_with("","a"))echo"not printed\n";// false

空文字に関しては、受理済のstr_containsのRFCの挙動に従います。
これはJavaやPythonなどと共通の動作です。

Backward Incompatible Changes

ユーザランドに同名の関数がある場合は競合します。

Proposed PHP Version(s)

PHP8

RFC Impact

・SAPI:全てのPHP環境に関数が追加されます
・エクステンション:無し
:Opcache:無し
・New Constants:無し
・php.ini Defaults:無し

Votes

投票は2020/05/04まで。
投票者の2/3+1の賛成で受理されます。

Patches and Tests

https://github.com/php/php-src/pull/5300

References

他言語の類似機能
・JavaScript: String#startsWith() / String#endsWith()
・Python: str#startswith() / str#endswith()
・Java: String#startsWith() / String#endsWith()
・Ruby: String#start_with?() / String#end_with?()
・Go: strings.HasPrefix() / strings.HasSuffix()
・Haskell: Data.String.Utils.startswith / Data.String.Utils.endswith
・MATLAB: startsWith()) / endsWith()

bugs.php.net
bug #50434 / bug #60630 / bug #67035 / bug #74449

過去のRFC
PHP RFC: rfc:add_str_begin_and_end_functions

Rejected Features

大文字小文字を区別しない版とマルチバイト版は、以前のRFCには含まれていましたが、このRFCでは廃止されました。
理由はstr_containsを参照してください。

感想

PHPの文字列関数ってやたら大量に用意されてるわりに意外と基本的なところが抜けていたのですが、PHP8でstr_continsとこの関数が追加されたことによって、テキスト処理に必要なものは出揃うことになったのではないでしょうか。

他に必要なのって何かありますかね。デフォルト関数の命名規則とか?

【PHP8.0】なんでもあり型が書けるようになる

ジェネリクスではない…ジェネリクスではないのだよ………

ざっくり言うとvar_dump()の型引数です。
var_dumpにはプリミティブ値にオブジェクトにリソース型にと、どんな値でも渡すことができるのですが、PHP7.4時点の型システムではvar_dumpの引数の型を表すことができません。
PHP8.0で導入予定のunion型を使うとarray|bool|callable|int|float|null|object|resource|stringとなるのですが、実はresource型はPHP8.0でもまだ使えないので、mixed型を完全に再現することはできません。

ということでMixed Type v2のRFCが提出されました。
投票は2020/05/21まで、受理には2/3+1の賛成が必要です。
が2020/05/11時点では賛成35反対6で、おそらく受理されます。

Introduction

PHP7のスカラー型、7.1のnull許容型、7.2のobject型、そして最新8.0のUNION型とPHPの型システムは進化し続けており、PHPの開発者はほとんどの関数において引数と返り値、そしてプロパティについて明示的に型情報を宣言することができるようになりました。

しかし、PHPは常に型をサポートしてきたわけではありません。
そしてこれは、型情報が欠落している際にその意味が曖昧になってしまうという問題に繋がります。

・特定の型に決まっているが、プログラマが宣言を忘れてしまった
・特定の型に決まっているが、古いバージョンのPHPと互換を保つためにあえて省略している
・現在のPHPの型システムでは表現できない型である

明示的なmixed型を用意することで、引数や返り値、プロパティに型を追加して、型情報を忘れていたわけではなく、正確に指定できなかったりあえて広げているのだという主張をを示すことができます。

現在のところmixed型はPHPDocの中でのみ使用することができますが、これは適切ではありません。
PHPDocでmixed型が使用されている顕著な例としては、PHP標準ライブラリ関数の返り値などがあります。
ネイティブにmixed型があれば、これらをより正確に表現することができるでしょう。

またmixed型はPHPマニュアルにおいても広く使用されています。

var_dump(mixed$expression[,mixed$...]):void

Proposal

PHPの型システムにmixed型を追加します。
これはarray|bool|callable|int|float|null|object|resource|stringと等価です。
これはPHPの継承時の型検査の実装に適合する正しい動作です。

LSP, Covariance and Contravariance

このProposalは、リスコフの置換原則に準拠しています。

PHP7.4以降、PHPは共変戻り値と反変パラメータに対応しています。

PHPではLSP原則に従うように、パラメータの拡大を許容しています。
サブクラスにおいて、親クラスより広い、特殊でない型を使用することができます。

PHPではLSP原則に従うように、返り値の縮小を許容しています。
サブクラスにおいて、親クラスより狭い、特殊な型を使用することができます。

Parameter types are contravariant

引数は、特定の型からmixed型に拡大することができます。

// 正しい例classA{publicfunctionfoo(int$value){}}classBextendsA{// intからmixedに拡大は許可publicfunctionfoo(mixed$value){}}

引数の縮小は、LSP原則に違反するため許可されません。

// 不正な例classA{publicfunctionfoo(mixed$value){}}classBextendsA{// mixedからintに縮小は不可// Fatal errorが出るpublicfunctionfoo(int$value){}}### Return types are covariant返り値は`mixed`型から特定の型に縮小することができます```php// 正しい例classA{publicfunctionbar():mixed{}}classBextendsA{// mixedからintに縮小は許可publicfunctionbar():int{}}

返り値の拡大は、LSP原則に違反するため許可されません。

// 不正な例classC{publicfunctionbar():int{}}classDextendsC{// intからmixedに拡大は不可// Fatal errorが出るpublicfunctionbar():mixed{}}

Property types are invariant

プロパティ型指定のRFCに従い、プロパティの型は不変です。

// 不正な例classA{publicmixed$foo;publicint$bar;public$baz;}classBextendsA{// プロパティ型は縮小不可// Fatal errorが出るpublicint$foo;}classCextendsA{// プロパティ型は拡大不可// Fatal errorが出るpublicmixed$bar;}classDextendsA{// 未指定にmixed型を追加するのも駄目// Fatal errorが出るpublicmixed$baz;}classEextendsA{// 型指定の削除も駄目// Fatal errorが出るpublic$foo;}

Void return type

void型の返り値については、LSPに適合していたとしても拡張は許可されません。

classA{publicfunctionbar():void{}}classBextendsA{// Fatal error: Declaration of B::bar(): int must be compatible with A::bar(): voidpublicfunctionbar():int{}}

このRFCは、既存の振る舞いに従います。
すなわち、void型をmixed型に広げることはできません。

Signature checking of function when no parameter type present

引数に型が存在しない場合の型チェックは、mixed型が指定されたかのように動作します。

classA{// 引数の型がないのでmixedとみなすpublicfunctionfoo($value){}}classBextendsA{// mixed型を追加したが、親クラスと動きは同じpublicfunctionfoo(mixed$value){}}classCextendsB{// mixed型を削除したが、親クラスと動きは同じpublicfunctionfoo($value){}}classDextendsB{publicfunctionfoo(mixed$value=null){}}

現在のところ、これはクラスの継承に限った動作です。

PHPで型を定義できるようになれば、他のところでも動くようになるかもしれません。

Signature checking of function when no return type present

返り値に型が指定されていない場合の型チェックは、mixed|void型が指定されたかのように動作します。

サブクラスでオーバーロードする際は、返り値を未指定にするか、void型にするか、mixed型およびそのサブタイプの何れかを指定しなければなりません。
そして、一度変更したあとの型を未指定に戻すことはできません。

classA{// 返り値に型がないのでmixed|voidとみなすpublicfunctionfoo(){}}classBextendsA{// mixedを指定した。voidは禁止になるpublicfunctionfoo():mixed{}}classCextendsB{// mixed|voidはmixedより広いのでNG// Fatal errorが出るpublicfunctionfoo(){}}classDextendsB{// voidはmixedのサブタイプではないのでNG// Fatal errorが出るpublicfunctionfoo():void{}}

The mixed|void union type

このRFCは、mixed|voidのUNION型は必要ないので許可しないという立場です。
今後ユースケースが見つかれば許可される可能性はあります。

Nullability

mixed型にはnullが含まれます。
従ってmixed型のnull許容型は情報の重複となります。

このRFCは、mixed型のnull許容型を許容しないという立場です。
今後ユースケースが見つかれば許可される可能性はありますが、その際はどの冗長な型指定を許可して、どの冗長な型指定は許可しない、という議論が必要になるでしょう。

// NG、既にnull許容なのでfunctionfoo(?mixed$arg){}// NG、既にnull許容なのでfunctionbar():?mixed{}

Explicit returns

返り値にmixed型を使用する場合、明示的にreturnを記述する必要があります。
さもなければTypeErrorが発生します。

functionfoo():mixed{}foo();// Uncaught TypeError: Return value of foo() must be of the type mixed, none returned

既存のnull許容型と同じ動作です。

functionbar():?int{}bar();// Uncaught TypeError: Return value of bar() must be of the type int or null, none returned

Resource 'type'

PHPではresource型の値を変数に割り当てることができますが、ユーザランドでは引数、返り値、プロパティの型としてresource型を使用することができません。
このRFCの立場としては、resource型はresource型チェックをパスすべきである、というものです。

Mixed vs any

PHPではマニュアルやPHPStanなどの静的解析ツールで広くmixed型が使われているため、mixedになりました。
またmixedはPHP7以降弱い予約語とされていますが、anyは予約語に含まれません。

RFC Impact

Proposed PHP Version(s)

PHP8.0

Backward Incompatible Changes

クラス名としてのmixedが禁止されますが、PHP7.0以降mixedは弱い予約語です。

To SAPIs

特になし。

To Existing Extensions

特になし。

To Opcache

特になし。

Vote

2020/05/07に投票開始、2020/05/21に投票終了。
受理には2/3+1の賛成が必要です。

Patches and Tests

GitHub Pull request #5313

References

PHP RFC: Reserve Even More Types in PHP 7
phpDocumentor type reference

感想

これ、UNION型のRFCの将来の展望にある型宣言そのものですよね。
ついでだから型宣言自体もできるようにしてしまえばいいのでは。

ということでPHP8からmixed型が使えるようになります。

var_dumpのような、仕様としてあらゆる値を受け取る必要のある関数のためにこれが必要なことは確かでしょう。

しかし、ユーザランドで何も考えず適当にこれを使って大惨事、という未来が目に見えますね。
まあでも、そんな人はそもそも型引数を書かないだろうから問題ないかな?

HTTP リクエストの Host ヘッダフィールドを知ろう

この記事はRFC7230をもとにしています。つまみ食い読みをしているので、間違っていたらすみません。編集リクエストをいただけると幸いです。


HTTP では、クライアントサーバーモデルに基づき、クライアントがサーバーへリソースを要求(リクエスト)し、サーバーはそれに応答(レスポンス)を返します。

クライアントやサーバーが発するものはメッセージと呼ばれます。メッセージは

  • 0個以上のヘッダフィールド、
  • ヘッダフィールドの終わりを示す空の行、
  • オプション(あってもなくてもよい)としてメッセージボディ

からなります。

この記事では HTTP リクエストの特に Host ヘッダフィールドについて理解することを目的とします。

HTTP リクエストメッセージとレスポンスメッセージは、以下のようなものです。(RFC7230 §2.1から引用)

   Client request:

     GET /hello.txt HTTP/1.1
     User-Agent: curl/7.16.3 libcurl/7.16.3 OpenSSL/0.9.7l zlib/1.2.3
     Host: www.example.com // ←ここが Hostヘッダフィールド
     Accept-Language: en, mi


   Server response:

     HTTP/1.1 200 OK
     Date: Mon, 27 Jul 2009 12:28:53 GMT
     Server: Apache
     Last-Modified: Wed, 22 Jul 2009 19:15:56 GMT
     ETag: "34aa387-d-1568eb00"
     Accept-Ranges: bytes
     Content-Length: 51
     Vary: Accept-Encoding
     Content-Type: text/plain

     Hello World! My payload includes a trailing CRLF.

HTTP リクエストの Host ヘッダフィールドは、アクセスしたい URI とポートの情報をもちます。

Host: www.example.com
もしくは
Host: www.example.com:80

サーバーは単一の IP アドレスについて複数のホストネームを持つことができます。どのホストネームでリソースを要求されたかによって、提供するリソースを振り分ける必要があります。HTTP リクエストを受け取ったサーバーは Host ヘッダを見ることによって、提供すべきリソースを決めることができます。

HTTP リクエストメッセージは必ず Host ヘッダフィールドを含む必要があります (MUST)。

上の例のリクエストメッセージの1行目

GET /hello.txt HTTP/1.1

のことをリクエストラインと呼びます。リクエストラインの GETの直後、この例では /hello.txtの部分をリクエストターゲットと言います。リクエストターゲットはターゲットの URI から作られ、その書き方は4種類あります。

Authority コンポーネント (johndoe@www.example.comみたいなもの、ユーザー名と @はなくてもいいので通常は www.example.comの部分) がターゲット URI に含まれる場合は、 Host ヘッダフィールドにも同じ値 (www.example.com) をもつ必要があります (MUST)。

逆にターゲット URI に authority コンポーネントが欠けている場合は、 Host ヘッダフィールドの値は空でなければなりません (MUST)。1

Host ヘッダフィールドの値はリクエストを扱うのに重要な情報ですから、ユーザーエージェント(ブラウザとか)はリクエストラインのすぐ直後に Host ヘッダを生成すべきです (SHOULD)。例えば http://www.example.org/pub/WWW/へのリクエストは

     GET /pub/WWW/ HTTP/1.1
     Host: www.example.org

というようになります。

HTTP/1.1 リクエストでは、クライアントはリクエストターゲットを absolute-form (リクエストターゲット参照) で書いた場合であっても Host ヘッダを送らなければなりません (MUST)。Host を実装していない可能性がある古代の HTTP/1.0 プロキシはを経由しても Host 情報が渡されるようにするためです。

プロキシが absolute-form のリクエストターゲットを受け取ったとき、プロキシは Host ヘッダフィールドを無視しリクエストターゲットのホスト情報で置き換えなければなりません (MUST)。そのようなリクエストを転送するプロキシも同様です。

Host ヘッダフィールドはアプリケーションレベルでのルーティング機構として振る舞うため、共有キャッシュポイズニングや意図しないサーバーへのリダイレクトを狙うマルウェアの標的となりがちです。透過プロキシがリクエストを内部サーバーに Host フィールドの値に基づいて振り分けていたり、共有キャッシュのキャッシュキーとして用いられていたりしていて、プロキシを通る通信がそのホストにとって有効な IP をターゲットとしているかの検証をしていない場合には、特に脆弱です。

Host ヘッダフィールドがない、または複数ある、または無効な値になっている HTTP/1.1 リクエストに対してサーバーは 400 Bad Request を返さなければなりません (MUST)。


  1. Host ヘッダフィールドが空、すなわち authority コンポーネントがない状況というのはおそらく何らかの異常が起きた状況だと思うのですが、具体的にはどのような状況なのでしょうか。ご存知の方がいらっしゃいましたらコメント欄等で教えていただけると幸いです。 

【PHP8.0】例外をcatchしたいけど何もしたくない

例外をcatchしたいけど何もしたくない。

try{foo();}catch(Throwable$e){// 何もしない}

何もしないのにわざわざ変数に受け取るのって無駄じゃありませんか?

というわけでnon-capturing catchesというRFCが提出されました。

PHP RFC: non-capturing catches

Introduction

今のところ、PHPは例外を明示的に変数でキャプチャする必要があります。

try{foo();}catch(SomeException$ex){die($ex->getMessage());}

しかしながら、ときにはその変数を使わない場合もあります。

try{changeImportantData();}catch(PermissionException$ex){echo"You don't have permission to do this";}

これを見た人は、プログラマが意図してこの変数を使わなかったのか、あるいはバグなのかがわかりません。

Proposal

例外を変数に受け取らずcatchできるようにします。

try{changeImportantData();}catch(PermissionException){// catchした変数を使わないという意図が明白echo"You don't have permission to do this";}

Prior art

7年前にあった似たようなRFCは、以下のように例外名も省略可能にするという理由で否定意見が多数でした。

try{foo();}catch{bar();}

いっぽう、このRFCは肯定的な反応が多く、再検討の余地があります。

Backward Incompatible Changes

後方互換性を壊す変更はありません。

Proposed PHP Version(s)

PHP8.0

RFC Impact

特になし。

Vote

投票は2020/05/24まで、投票者の2/3の賛成で受理されます。
このRFCは賛成48反対1の圧倒的多数で受理されました。

Patches and Tests

https://github.com/php/php-src/pull/5345

References

メーリングリスト

感想

このRFCが意図しているところは決して例外の握り潰しなどではなく、例外処理のロジックに例外の中身を使わないときに省略できるというものです。
変数に受け取る処理がなくなるので速度も速まることでしょう。

しかしですな、こんな機能があったら絶対にこんなコードを書く奴が出てくるわけですよ。

PHP8
try{foo();}catch(Exception){}

いやまあ、こんなの書いてしまう人は今でもやってると思いますけどね。

PHP7
try{foo();}catch(Exception$e){}

なら別にあってもいいか。

劇的に便利になるというわけではないですが、ちょっと気が利く書き方ができるようになりますね。

最後にもう一度言いますが、冒頭のコードは悪い例なので決して真似してはいけません。

【PHP8.0】PHPにオブジェクト初期化子が導入される

これまで何度も塩漬けにされたり却下されたりしていたオブジェクト初期化子ですが、ついにPHP8.0で導入されることになりました。
オブジェクト初期化子が何かというとこれです。

classHOGE{publicfunction__construct(privateint$x){// $HOGE->xが生える}}

これはオブジェクト初期化子でいいのか?

日本語で何と表すのか適切な単語が思いつかなかったのでとりあえずオブジェクト初期化子としておきます。
愚直に訳すと"コンストラクタ引数昇格"ですが、そんな単語は無いうえに型昇格と紛らわしいです。
引数プロパティ宣言パラメータプロパティ宣言もほぼ使われてないし何と表現すればいいのだろう。
きっと誰かが適切な語をプルリクしてくれるはず。

以下は該当のRFC、PHP RFC: Constructor Property Promotionの日本語訳です。

PHP RFC: Constructor Property Promotion

Introduction

PHPでは現在のところ、オブジェクトにプロパティを定義するだけでも同じことを複数回書かなければならないため、多くの無駄が必要です。
以下の単純なクラスを考えてみましょう。

classPoint{publicfloat$x;publicfloat$y;publicfloat$z;publicfunction__construct(float$x=0.0,float$y=0.0,float$z=0.0,){$this->x=$x;$this->y=$y;$this->z=$z;}}

プロパティの表記は、1:プロパティの宣言、2:コンストラクタの引数、3:プロパティの代入で3回も繰り返されます。
さらにプロパティの型も2箇所に書かなければなりません。

プロパティ宣言とコンストラクタ以外には何も含まれていないバリューオブジェクトでは特に、多くの重複によって変更が複雑になり、エラーを起こしやすいものとなります。

このRFCでは、プロパティの定義とコンストラクタを組み合わせるショートハンド構文の導入を提案します。

PHP8
classPoint{publicfunction__construct(publicfloat$x=0.0,publicfloat$y=0.0,publicfloat$z=0.0,){}}

このショートハンド構文は、前述の例と厳密に同じで、より短く書くことができます。
構文は姉妹言語Hackから採用しています。

Proposal

コンストラクタの引数にpublic/protected/private何れかが記述されている場合、その引数は"promoteされた引数"とします。
promoteされた引数には、同じ名前のプロパティが追加され、値が割り当てられます。

Constraints

promoteはabstractではないクラスのコンストラクタでのみ記述可能です。
従って、以下のような構文は使用不能です。

// エラー:コンストラクタではないfunctiontest(private$x){}abstractclassTest{// エラー:abstractなので駄目abstractpublicfunction__construct(private$x);}interfaceTest{// エラー:interfaceも駄目publicfunction__construct(private$x);}

一般的でない使い方ですが、トレイトでは使用可能です。

対応する可視性キーワードはpublic/protected/privateのみです。

classTest{// エラー:varはサポートしてないpublicfunction__construct(var$prop){}}

promoteされた引数によるプロパティは、通常のプロパティと全く同じ扱いになります。
特に注意点として、同じプロパティを二度宣言することはできません。

classTest{public$prop;// Error: Redeclaration of property.publicfunction__construct(public$prop){}}

また、プロパティにすることのできないcallable型は使用することができません。

classTest{// Error: Callable type not supported for properties.publicfunction__construct(publiccallable$callback){}}

promoteされたプロパティはプロパティ宣言と同義であるため、デフォルトがNULLの場合はNULL許容型を明示しなければなりません。

classTest{// Error: Using null default on non-nullable propertypublicfunction__construct(publicType$prop=null){}// こっちはOKpublicfunction__construct(public?Type$prop=null){}}

可変長引数をpromoteすることはできません。

classTest{// エラーpublicfunction__construct(publicstring...$strings){}}

理由としては、明示する引数の型(ここではstring)と、実際に渡される引数の型(ここではstringの配列)が異なるからです。
$stringsプロパティをstringの配列にすることも可能ですが、それではわかりづらくなります。

promoteプロパティと明示的なプロパティ宣言を組み合わせることは可能です。
またpromoteプロパティとpromoteされない引数を同時に渡すことも可能です。

// 正しいclassTest{publicstring$explicitProp;publicfunction__construct(publicint$promotedProp,int$normalArg){$this->explicitProp=(string)$normalArg;}}

Desugaring

promoteプロパティはただのシンタックスシュガーであり、全てのpromoteプロパティに対して以下の変換が適用されます。

// シンタックスシュガーclassTest{publicfunction__construct(publicType$prop=DEFAULT){}}// こう展開されるclassTest{publicType$prop;publicfunction__construct(Type$prop=DEFAULT){$this->prop=$prop;}}

自動的に宣言されるプロパティの可視性と型は、promoteプロパティの可視性および型と同じになります。
注目すべき点は、プロパティにデフォルト値は適用されず(つまり、未初期化で始まります)、コンストラクタ引数でのみ指定されるところです。

プロパティ宣言時にもデフォルト値を指定したほうがよいようにも思えますが、将来的にデフォルト値で指定することが望ましくなるであろう理由が存在します。

ひとつめは、プロパティのデフォルト値に任意の式を利用できるようにする拡張の可能性です。

// FROMclassTest{publicfunction__construct(publicDependency$prop=newDependency()){}}// TOclassTest{publicDependency$prop/* = new Dependency() */;publicfunction__construct(Dependency$prop=newDependency()){$this->prop=$prop;}}

こうなると、プロパティ宣言時とデフォルト値でオブジェクトを2回構築することとなるため望ましくありません。

また、新潟アクセス修正子のルールではプロパティでデフォルト値を宣言すると、コンストラクタで代入することもできなくなります。

promote引数が参照であった場合、プロパティも参照になります。

// FROMclassTest{publicfunction__construct(publicarray&$array){}}// TOclassTest{publicarray$array;publicfunction__construct(array&$array){$this->array=&$array;}}

promoteプロパティへの引数の割り当ては、コンストラクタの冒頭で行われます。
従って、コンストラクタ内でも引数とプロパティの両方にアクセスすることが可能です。

// 動作するclassPositivePoint{publicfunction__construct(publicfloat$x,publicfloat$y){assert($x>=0.0);assert($y>=0.0);}}// こっちも動作するclassPositivePoint{publicfunction__construct(publicfloat$x,publicfloat$y){assert($this->x>=0.0);assert($this->y>=0.0);}}

Reflection

リフレクションおよびその他の解析機構で見ると、シンタックスシュガーを解除した後の状態になります。
すなわち、promoteプロパティは明示的に宣言されたプロパティのように見え、promote引数は通常のコンストラクタ引数のように見える、ということです。

PHPは引数に関するDocコメントを公開していませんが、promoteプロパティのDocコメントも保持されます。

classTest{publicfunction__construct(/** @SomeAnnotation() */public$annotatedProperty){}}$rp=newReflectionProperty(Test::class,'annotatedProperty');echo$rp->getDocComment();// "/** @SomeAnnotation */"

この例のように、promoteプロパティではDocコメントベースのアノテーションを使用することができます。

また、2メソッドが追加されます。

ReflectionProperty::isPromoted()は、promoteプロパティであればtrueを返します。
ReflectionParameter::isPromoted()は、promote引数であればtrueを返します。

プロパティがpromoteされたかどうかを気にする場面はほとんど存在しないと思われますが、この情報によって元のコードをより簡単に再構築することができます。

Inheritance

オブジェクト初期化子は継承することができますが、特に特筆すべきようなことはありません。
abstrautを含む典型的な継承のユースケースを以下に示します。

abstractclassNode{publicfunction__construct(protectedLocation$startLoc=null,protectedLocation$endLoc=null,){}}classParamNodeextendsNode{publicfunction__construct(publicstring$name,publicExprNode$default=null,publicTypeNode$type=null,publicbool$byRef=false,publicbool$variadic=false,Location$startLoc=null,Location$endLoc=null,){parent::__construct($startLoc,$endLoc);}}

ParamNodeクラスでいくつかのpromoteプロパティを宣言し、さらに二つの普通の引数を親コンストラクタに転送しています。
これは以下のように展開されます。

abstractclassNode{protectedLocation$startLoc;protectedLocation$endLoc;publicfunction__construct(Location$startLoc=null,Location$endLoc=null,){$this->startLoc=$startLoc;$this->endLoc=$endLoc;}}classParamNodeextendsNode{publicstring$name;publicExprNode$default;publicTypeNode$type;publicbool$byRef;publicbool$variadic;publicfunction__construct(string$name,ExprNode$default=null,TypeNode$type=null,bool$byRef=false,bool$variadic=false,Location$startLoc=null,Location$endLoc=null,){$this->name=$name;$this->default=$default;$this->type=$type;$this->byRef=$byRef;$this->variadic=$variadic;parent::__construct($startLoc,$endLoc);}}

プロパティへの代入は、親コンストラクタが呼ばれる前に行われることに注意してください。
これはコーディングスタイルとして一般的ではありませんが、動作に影響が出るようなことはほぼありません。

Attributes

PHP8ではアトリビュートも導入されるため、相互作用を考慮する必要があります。
アトリビュートは、プロパティと引数の両方で使用することができます。

classTest{publicfunction__construct(<<ExampleAttribute>>publicint$prop,){}}

このコードがどのように解釈されるか決める必要があります。
1. アトリビュートは引数にのみ適用する。
2. アトリビュートはプロパティにのみ適用する。
3. アトリビュートは引数とプロパティの両方に適用する。
4. 曖昧さを避けるためエラーにする

// Option 1: アトリビュートは引数にのみ適用するclassTest{publicint$prop;publicfunction__construct(<<ExampleAttribute>>int$prop,){}}// Option 2: アトリビュートはプロパティにのみ適用するclassTest{<<ExampleAttribute>>publicint$prop;publicfunction__construct(int$prop,){}}// Option 3: アトリビュートは引数とプロパティの両方に適用するclassTest{<<ExampleAttribute>>publicint$prop;publicfunction__construct(<<ExampleAttribute>>int$prop,){}}// Option 4: 曖昧さを避けるためエラーにする

このRFCでは3番目、つまり引数とプロパティの両方に適用することを提案しています。
これが最も柔軟性の高い方法だからです。

ただし、これは実装に依ると考えています。
PHP8の実装に関わる作業で、アトリビュートをプロパティにのみ配置した方がよいと判明した場合は、そのように変更される場合があります。

Coding Style Consideration

このセクションではコーディングスタイルの推奨について解説します。
規程ではありません。

promoteプロパティを使用する場合、コンストラクタをクラス最初のメソッドとして、明示的なプロパティ宣言の直後に配置することをお勧めします。
これにより、全ての全てのプロパティが先頭にまとめられ、一目でわかるようになります。
静的メソッドを最初に配置することを要求しているコーディング規約は、コンストラクタを最初に配置するよう規約を調整する必要があります。

promoteプロパティに@paramアノテーションを使用している場合、ドキュメントツールは@varアノテーションも含まれているものとして解釈されるべきです。

// 元のコードclassPoint{/**
     * Create a 3D point.
     *
     * @param float $x The X coordinate.
     * @param float $y The Y coordinate.
     * @param float $z The Z coordinate.
     */publicfunction__construct(publicfloat$x=0.0,publicfloat$y=0.0,publicfloat$z=0.0,){}}// こう解釈するclassPoint{/**
     * @var float $x The X coordinate.
     */publicfloat$x;/**
     * @var float $y The Y coordinate.
     */publicfloat$y;/**
     * @var float $z The Z coordinate.
     */publicfloat$z;/**
     * Create a 3D point.
     *
     * @param float $x The X coordinate.
     * @param float $y The Y coordinate.
     * @param float $z The Z coordinate.
     */publicfunction__construct(float$x=0.0,float$y=0.0,float$z=0.0,){$this->x=$x;$this->y=$y;$this->z=$z;}}

最後に、promoteプロパティは、あくまで一般的なケースをカバーするための便利な省略記法であるに過ぎないことに注意してください。
promoteプロパティはいつでも明示的なプロパティに書き換えることができます。
そのため、この変更は下位互換性を壊すことはありません。

Backward Incompatible Changes

下位互換性のない変更はありません。

Future Scope

Larryが、この機能と他の機能を組み合わせることによってオブジェクト初期化を改善する方法について、より深いビジョンを提供しています

Prior Art

この機能、あるいは類似した機能は多くの言語でサポートされています。
Hack
TypeScript
Kotlin

先行するRFCが存在します。
Automatic property initialization プロパティ宣言は必要とする、より弱い形です。
Constructor Argument Promotion このRFCとほとんど同じです。
Code free constructor Kotlinの文法に基づいています。

Vote

投票期間は2020/05/29まで、2/3+1の賛成が必要です。
このRFCは賛成46反対10で受理されました。

感想

プロパティを書くのが格段に楽になりますね。
後から見るときにプロパティが宣言されているのかどうかちょっとわかりにくそうですが、この機能が使えるのはコンストラクタだけなのでそこだけ抑えていれば大丈夫でしょう。
コンストラクタだけではなく任意のメソッドで使えると便利では、と一瞬思ったものの、これを無制限に使えると完全に収拾が付かなくなってしまうので、やはりコンストラクタだけに留めておくのが賢明そうですね。

【PHP8.0】厳密なswitch文ことmatch式が使えるようになる

PHPがよく言われる問題点のひとつとして、switch曖昧な比較であるということが挙げられます。

switch($x){case1:'$xは1だよ';break;case"1":'$xは"1"だよ';break;}

case "1"に到達することは決してありません。

ということで厳密な比較を用いるswitchことmatch構文のRFCが提出されました。
以下はMatch expression v2の日本語訳です。

PHP RFC: Match expression v2

Proposal

このRFCは、switchに似ていますが、より安全なセマンティクスを持つmatch構文の提案です。

例として、Doctrineのクエリパーサを挙げます。

// Beforeswitch($this->lexer->lookahead['type']){caseLexer::T_SELECT:$statement=$this->SelectStatement();break;caseLexer::T_UPDATE:$statement=$this->UpdateStatement();break;caseLexer::T_DELETE:$statement=$this->DeleteStatement();break;default:$this->syntaxError('SELECT, UPDATE or DELETE');break;}// After$statement=match($this->lexer->lookahead['type']){Lexer::T_SELECT=>$this->SelectStatement(),Lexer::T_UPDATE=>$this->UpdateStatement(),Lexer::T_DELETE=>$this->DeleteStatement(),default=>$this->syntaxError('SELECT, UPDATE or DELETE'),};

Differences to switch

switch構文と異なる点です。

Return value

後で使いたい値をswitch内で生成することは非常によくあることです。

switch(1){case0:$result='Foo';break;case1:$result='Bar';break;case2:$result='Baz';break;}echo$result;//> Bar

そして$resultに代入し忘れることもよくあるミスです。
さらに深くネストされていた場合は、$resultがしっかり代入されているか確認するのもたいへんです。
それに対し、matchは実行した結果が評価される式です。
これによって多くの定型文を削除することができ、代入忘れというミスがなくなります。

echomatch(1){0=>'Foo',1=>'Bar',2=>'Baz',};//> Bar

No type coercion

switch文は緩やかな比較==を使います。
これは直感に反する結果をもたらすことがあります。

switch('foo'){case0:$result="Oh no!\n";break;case'foo':$result="This is what I expected\n";break;}echo$result;//> Oh no!

match式は厳密な比較===で比較します。
strict_typesの設定に関わらず常に厳密です。

echomatch('foo'){0=>"Oh no!\n",'foo'=>"This is what I expected\n",};//> This is what I expected

No fallthrough

switchフォールスルーは、多くの言語でバグの温床となっています。
caseは明示的にbreakしないかぎり、次のcaseへと実行が継続されます。

switch($pressedKey){caseKey::RETURN_:save();// break忘れたcaseKey::DELETE:delete();break;}

match式では、暗黙のbreakを付与することで、この問題を解決します。

match($pressedKey){Key::RETURN_=>save(),Key::DELETE=>delete(),};

複数条件で同じコードを実行したい場合は、条件をカンマで区切ります。

echomatch($x){1,2=>'Same for 1 and 2',3,4=>'Same for 3 and 4',};

Exhaustiveness

switchでよくあるもうひとつの問題は、全てのcaseに対応していない場合の処理です。

switch($operator){caseBinaryOperator::ADD:$result=$lhs+$rhs;break;}// BinaryOperator::SUBTRACTを渡しても何も起こらない

これが原因で、よくわからないところでクラッシュしたり、想定していない動作をしたり、なお悪いときにはセキュリティホールの原因になったりします。

$result=match($operator){BinaryOperator::ADD=>$lhs+$rhs,};// BinaryOperator::SUBTRACTを渡すと例外が発生する

match式はどのcaseにも当てはまらなかった場合はUnhandledMatchErrorを発するので、間違いに早期に気付くことができます。

Miscellaneous

Arbitrary expressions

matchする条件を任意の式にすることができます。
比較条件はswitch同様上から順に判定され、マッチした以後の条件は評価されません。

$result=match($x){foo()=>...,$this->bar()=>...,// foo()がマッチしたらここは呼ばれない$this->baz=>...,// etc.};

Future scope

この項目は将来の予定であり、このRFCには含まれません。

Blocks

このRFCでは、match式の本文はひとつの式でなければなりません。
ブロックを許すかについては、別のRFCで議論します。

Pattern matching

パターンマッチングについても検討しましたが、このRFCには含めないことにしました。
パターンマッチングは非常に複雑であり、多くの調査が必要です。
パターンマッチングについては別のRFCで議論します。

Allow dropping (true)

$result=match{...};// ↓と同じ$result=match(true){...};

Backward Incompatible Changes

matchがキーワードreserved_non_modifiersとして追加されます。
以下のコンテキストで使用することができなくなります。
・名前空間
・クラス名
・関数名
・グローバル定数

メソッド名およびクラス定数としては引き続き使用可能です。

Syntax comparison

他言語でのmatch構文

Vote

投票は2020/07/03まで、投票者の2/3の賛成で受理されます。
2020/06/22時点では賛成20反対1となっていて、よほどの問題でも発生しないかぎり受理されるでしょう。

感想

switchでよく問題になっていた曖昧な比較やbreakし忘れといったミスが、構文レベルで不可能となります。
そのため、match式に従っておけばswitchに起因する問題はほぼ発生しなくなるでしょう。
またmatch全体が返り値を持ってるのも便利ですね。

そのかわり、case内部には1式しか書けないため、複数の変数値を変更したり入れ子にしたりといった複雑な処理を書くことは難しくなります。
また、あえてbreakを書かずに継続したい場合も面倒な書き方になります。

// 1ならfooとbarを、2ならbarだけ実行したいswitch($x){case1:foo();case2:bar();break;}// aftermatch($x){1=>foo()&&bar(),2=>bar(),};

{}で括って複数の文を書けるようにするかどうかは、アロー関数同様今後の課題となっています。

従って本RFCは、決してあらゆるswitchを置き換える構文ではなく、アロー関数のように一部のswitch文を置き換えることができる短縮構文という立ち位置になります。
しかし、よほど変なことでもしていないかぎり、大抵のswitch文はmatch式に置き換えることができると思います。
安全性のためにも、今後はできるだけmatch式を使っていくとよいでしょう。

Browsing Latest Articles All 41 Live