ジェネリックの詳細 – Stitcher.io

in Vlog

(jp) =

<!–

–>

前回の投稿で非常に退屈なジェネリックの例を示しましたが、今回はもっとうまくやります。

$users = new Collection<User>();

$slugs = new Collection<string>();

コレクション; これらはおそらくジェネリックが何であるかを説明する最も簡単な方法ですが、ジェネリックについて議論するときに誰もが話す例でもあります. 「ジェネリック」と「型を持つコレクション」を同じものと考える人は、実は珍しくありません。 絶対にそうではありません。

それでは、さらに 2 つの例を見てみましょう。

ここに呼ばれる関数があります app — Laravel のようなフレームワークを使用している場合、見覚えがあるかもしれません。この関数はクラス名を取り、依存関係コンテナーを使用してそのクラスのインスタンスを解決します。

function app(string $className): mixed

    return Container::get($className);

ここで、コンテナーがどのように機能するかを知る必要はありません。重要なのは、この関数が、要求したクラスのインスタンスを提供することです。

したがって、基本的には汎用関数です。 戻り値の型は、指定したクラス名の種類によって異なります。 そして、この関数にクラス名「UserRepository」を指定すると、UserRepository のインスタンスが返されるだけで、それ以外は何も返されないことを IDE や他の静的アナライザーも理解できれば素晴らしいことです。

function app(string $className): mixed
  

app(UserRepository::class); 

まあ、ジェネリックはそれを可能にします。

そして、これは私が秘密を守ってきたことを言及するのに良い時期だと思います. まあ、それは完全に真実ではありません。 あらゆる静的アナライザー — コードを実行せずに読み取るツール、IDE などのツール — は、ジェネリックに doc ブロック アノテーションを使用することに同意しています。


function app(string $className): mixed
  

確かに、これは最もきれいな構文ではなく、すべての静的アナライザーは、これが構文であるという単純な同意に依存しています — 公式の仕様はありません。 それにもかかわらず、それは機能します。 PhpStorm、Psalm、および PhpStan (これらは PHP の世界で最大の 3 つの静的アナライザーです) は、この構文をある程度理解しています。

PhpStorm などの IDE は、プログラマーがコードを記述しているときにフィードバックを提供するために使用します。また、Psalm や PhpStan などのツールは、コードベースを一括で分析し、主に型定義に基づいて潜在的なバグを検出するために使用します。

実際にこれを構築することができます app 私たちのツールが暗闇の中で動作しないように機能します。 もちろん、戻り値の型が正しいという保証は PHP 自体にはありません。PHP は、この関数の実行時の型チェックを行いません。 しかし、静的アナライザーが正しいと信頼できれば、実行時にこのコードが壊れる可能性はほとんどありません。

これは静的解析の驚異的な力です。コードを実行しなくても、実際にそれを確認できます。 そのほとんどは意図したとおりに機能します。 これらはすべて、ジェネリックを含む型のおかげです。

さらに複雑な例を見てみましょう。

Attributes::in(MyController::class)
    ->filter(RouteAttribute::class)
    ->newInstance()
    ->

ここには、属性を「照会」してその場でインスタンス化できるクラスがあります。 属性のリフレクション API がかなり冗長であることを知る前に属性を操作したことがある場合、この種のヘルパー クラスは非常に便利だと思います。

私たちが使用するとき filter メソッドに、属性のクラス名を付けます。 その後、 newInstance メソッドを使用すると、結果がフィルター処理されたクラスのインスタンスになることがわかっています。 繰り返しますが、私たちの IDE が私たちが話していることを理解してくれるとよいのですが。

ご想像のとおり、ジェネリックを使用すると、次のことが可能になります。


class Attributes

    
    public function filter(string $className): self
      
 
       
    public function newInstance(): mixed
      
    
    

単純型情報がいかに強力であるかを理解していただければ幸いです。 数年前までは、この種の洞察を機能させるには IDE プラグインが必要でしたが、今はタイプ情報を追加するだけです。

この最新の例は、ジェネリックに依存しているだけではありません。同じように重要な部分がもう 1 つあります。 型推論: ユーザーが型を指定しなくても型を「推測」する、または確実に決定する静的アナライザーの機能。 それが、あちらのクラス文字列アノテーションで起こっていることです。 IDE は、この関数に与えた入力をクラス名として認識し、その型をジェネリック型として推測できます。

したがって、すべてが解決されました。ジェネリックは PHP で利用可能であり、すべての主要な静的アナライザーはジェネリックを使用する方法を知っています。 うーん…いくつか注意点があります。

まず、ジェネリックがどのように見えるべきかについての公式の仕様はありません。現在、すべての静的アナライザーが独自の構文をプッシュできます。 今のところ、彼らはたまたま1つに同意しました。 しかし、将来の保証はほとんどありません。

2 つ目: 私の意見では、doc ブロックは最適ではありません。 それらは私たちのコードベースの重要性の低い部分のように感じます. 確かに、一般的な注釈は静的な洞察のみを提供し、ランタイム機能は提供しませんが、ランタイムの型チェックがなくても、静的分析がいかに強力であるかを見てきました。 型情報を「ドキュメント コメント」として扱うのは不公平だと思います。コード内でそれらの型の重要性を伝えていません。 これが、PHP 8 で属性を取得した理由です。属性が提供するすべての機能は、docblock アノテーションですでに可能でしたが、それだけでは十分とは思えませんでした。 ジェネリックも同様です。

そして最後に、適切な仕様がなければ、3 つの主要な静的アナライザーはすべてジェネリックの実装に違いがあります。 PhpStorm は、現時点で最も欠けているものです。 理想的には、PHP の内部からの公式仕様があるでしょう。 現在、ありません。

これらが、より永続的で持続可能な解決策に時間を投資する価値があると私が信じる主な理由です。 では、なぜ PHP にはまだ適切なジェネリックがないのでしょうか? 明確な仕様なしに doc ブロックに依存するのはなぜですか?

それは次の投稿で!

tpyoに気づきましたか? PR を送信して修正することができます。 このブログの最新情報を知りたい場合は、私をフォローしてください。 ツイッター または私のニュースレターを購読してください:

//platform.twitter.com/widgets.js

関連記事

前の投稿
ウィスコンシン州で最も深い湖を発見
次の投稿
ミシシッピ州で最も寒い場所を発見する