Page 1
PHP8 <<Attribute>>
2020-05-16 #phpkansai【オンライン】関西PHP勉強会
公開日:
by USAMI Kenta@tadsan
にオンラインのビデオ会議で開催された『関西PHP勉強会』でライトニングトーク(5分)として発表しました。
2020-05-16 #phpkansai【オンライン】関西PHP勉強会
近況
月から氏んでた
最近はやや元気
PHPカンファレンス関西にはPHP-Parserの話をしようと応募してました
はじめに
今回紹介する内容によって今すぐ何かが変わることはあまりない
少なくともコードをPHP7系から8に移行できないと使えない
これから一年くらいかけて対応するツールやフレームワークも徐々に出てくると思う
PHP8時代に心の準備だけしておこう
さて
RFC
PHPへの変更提案
全てのPHPへの変更はここで議決
ここを観察すれば次のPHPがわかる
ウォッチしてますか?
@PHPRFCBot
今年12月にリリース予定のPHP8.0に向けてさまざまな機能が提案
Feature freezeは7月だが既にPHP8向けにいろいろ決まってる
さて
RFCは受理されたが、実装はまだマージされてない
過去何度も提案されてきたが今回の仕様でようやく受理された
そもそもこれは何だ
このRFCはクラス・プロパティ・関数・メソッド・引数および定数の宣言に対する構文的メタデータの構造化された形式として「アトリビュート」を提案します。アトリビュートによって宣言に直接埋め込まれた構成ディレクティブを定義できます。
似たようなコンセプトは「アノテーション」としてJavaに、「アトリビュート」としてC#・C++・Rust・Hackに、そして「デコレータ」としてPython・JavaScriptにあります。
attributeの定訳としては「属性」。直接関係ないが同じ用語としてはHTMLでも非常に重要な概念。<a href="...">
これまでPHPは構造化されていない形式のメタデータとしてDoc-commentだけを提供しています。ただ、Doc-commentは単なる文字列であり、構造化情報を保持するための @ ベースの擬似言語がさまざまなPHPサブコミュニティによって提案されてきました。
Doc-commentはリフレクションAPI経由で実行時に文字列として取得できる
実行時に影響することもあるし、しないこともある特殊なやつ
/**
* これ
*/
/**
*
@return int
*/
/**
*
@phpstan-return 1|2
*/
/**
*
@deprecated
*/
/**
*
@Inject
*/
/**
*
@Inject(optional=true)
*/
各プロジェクトが雰囲気で定義してる
各プロジェクト固有タグは@phan-param みたいに共通のタグにprefixをつけたりアノテーションを\ で名前空間で区切ってる
文字列を解析してるだけだからPHPに存在しない名前付き引数も好き勝手に使えるぜ!!!11
‒ PHPerKaigi 2020 (Feb 9, 2020)
大雑把に言うとIDEや静的解析のヒント実行時メタプログラミングに分類できる
なんとなくの風潮として
@tag
は
タグ
、
@Anno("arg", attr=true)は
アノテーション
と呼び分け
あくまで「なんとなく」であって、各サブコミュニティが勝手に実装してるだけなので厳密な定義はない
区別はかなり曖昧だがPSR-19はタグカタログであり、アノテーションカタログではない
どちらにせよ、PHPスクリプトに書く以上の付加情報を記述できる
あるいは実装から分離してアノテーションとして記述することでAOPを実現
実行時メタプログラミングの温床
例:Go! AOP
そんなわけでAttributeが入ると
/**
* @
ExampleAttribute
*/
class Foo
{
// ...
}
<<
ExampleAttribute
>>
class Foo
{
// ...
}
// この記法は不採用
@:
ExampleAttribute
class Foo
{
// ...
}
Doc-commentから取得できるのは文字列なので、実行時に活用するにはそれを構文解析する必要
AttributeはDoc-commentと同じように実行時に取得でき、構造化されており構文解析不要
好き勝手な記法が使えるタグ/アノテーションと違ってAttributes v2仕様は単純な関数呼び出し風構文と静的な式
静的な式 = PHPで有効な式のうちリテラルと定数と演算子式で解決できる(実行時に変わらない)
たぶんPHP-Parserからもリフレクションと似たAPIが用意されて簡単に取得できるだろう
アトリビュートはクラスと同じようにuseで名前解決できる
アトリビュートはクラスにマッピングし、Reflectionからインスタンスがとれる
<<PhpAttribute>>
class MyAttr
{
function __construct($arg){
// 特にやることがなければ
// 実行時には何もしなくていい
}
}
ある意味ではコメントと同じで、取得されない限りAttributeは実行に影響を及ぼさない
先程のAttributeクラスは静的解析のためのヒントであって必須ではない
その意味でPythonのデコレータとは全然違う
アトリビュートを加味してインスタンスを生成する実行時のファクトリーまたはクラスローダーで近似させることはできる
明確な分類はできないが、タグよりもアノテーション系の方がアトリビュートで表現しやすい
PHPコンパイラ(処理系)のためのアトリビュートがあることが示唆されている(詳細はRFC範囲外)
PHPやるじゃん
ほんとに?
誰のためのアトリビュート?
コンパイラアトリビュート(処理系への指示)はなんとなくわかる
ユーザーランドアトリビュートは…?
ユースケースは…?
RFCで実例が紹介されている
これはわかる
これも… まあまあ
これは… そうなるね
ここまでくると…
もうつらたん
DSLを喜んで覚え直したいひとは居るのか?
移行対象ではなく例として考えれば、アノテーションベースDSLの新規実装コストは多少下がってそう
とはいえライブラリは既にあるし、コードインジェクションもキャッシュ機構があるので実行時コストには影響しない
実はPHP RFC:Named Argumentsも復活してPHP8に向けて議論されそうな雰囲気があるので影響あるかもね
<<Deprecated>>
アトリビュートの実際の利用例としての新しいRFC
trigger_error
(E_DEPRE
CATED)
相当のコードを生成する実行エンジン組み込みのアトリビュート
言語組み込みのアトリビュートがある意義もわかるし、ユーザーランドで再現もめんどいので助かるといえば助かる
関数やメソッド以外にプロパティや定数の非推奨化もできる
が、メーリングリストでは存在意義について割と揉めてる
ついでに引数へのアトリビュートの付けかたについても議論
function f(
$arg1,
$arg2
){}
function f(
<<Deprecated>>
$arg1,
$arg2
){}
引数のアトリビュートってほんとに必要なんですか…
そもそも名前空間
\Php\Attributes
\Deprecated
じゃなくていいの?
Attributesのfuture scopeの段階では名前空間がついてたのに、しれっとグローバル名前空間に移動している
Attributeが解決できない問題
/** @duplicated */
アノテーション名をタイプミスすると(上手に静的解析しない限り)実行時に無視される
<<Duplicated>>
アトリビュート名をタイプミスすると(静的解析しない限り)実行時に無視される
あと単純に名前空間との相性が悪くて、IDEや静的解析を使ってないとuseし忘れて無意味なおまじないとして残り…
この問題はアノテーションベースAOPで結構深刻だと思うんですけど皆さんどうやって解決してるんだろ
全部のタグ/アノテーションがアトリビュートに移行されるの?
されないと思う
@param 1|2 $arg
/**
*/
function f(
int $arg1
){}
(イメージ)アトリビュートで置換
use PHPStan\Param as param;
function f(
<<param("1|2")>>
int $arg1
){}
IDEの入力補完があったとしても書きにくい
Attributeの明日はどっちだ
PHP先生の次回作にご期待ください
