ホームページ  >  記事  >  バックエンド開発  >  PHP でジェネリックが使用できない理由を分析してみましょう

PHP でジェネリックが使用できない理由を分析してみましょう

WBOY
WBOY転載
2022-03-29 10:29:575517ブラウズ

この記事では、PHP に関する関連知識を提供し、主に PHP でジェネリックスが使用できない理由を紹介します。次に、ジェネリックスと PHP の背後にある状況を掘り下げて、ジェネリックスの型がサポートされていない理由を理解します。まだ第一級市民ですが、これが役立つことを願っています。

PHP でジェネリックが使用できない理由を分析してみましょう

推奨学習: 「PHP チュートリアル

PHP でジェネリックスを使用できない理由

usジェネリックと PHP の背後で何が起こっているのかを詳しく見ていきます。ジェネリックが PHP の第一級市民としてまだサポートされていない理由を理解することは非常に興味深く、重要です。 ###############見てみましょう。

PHP にはジェネリックはありません。これが昨年のニキータの結論です。これはまったく実現不可能です。 PHP でジェネリックが使用できない理由を分析してみましょう

ニキータがこのように言っている理由を理解するには、ジェネリックがどのように実装されているかを見る必要があります。一般に、考えられるアプローチは 3 つあり、ジェネリックスをサポートするプログラミング言語は、主にこれら 3 つのアプローチのいずれかを使用します。

最初のものは単相ジェネリックと呼ばれます。このシリーズの最初の記事に戻りましょう。このコレクションの例を示しました。

class StringCollection extends Collection
{
    public function offsetGet(mixed $key): string 
    { /* … */ }
}
class UserCollection extends Collection
{
    public function offsetGet(mixed $key): User 
    { /* … */ }
}

達成する必要があるコレクションの種類ごとにコレクション クラスを手動で作成できることを説明しました。ワークロードは膨大になり、コードも大量になりますが、うまくいきます。

単型ジェネリックはまさに​​それを行いますが、舞台裏で自動的に行われます。実行時には、PHP はジェネリック Collection クラスについては認識せず、むしろ 2 つ以上の特定の実装について認識します。

$users = new Collection<User>();
// Collection_User
$slugs = new Collection<string>();
// Collection_string

単相ジェネリックは完全に有効なアプローチです。たとえば、Rust ではこれらが使用されます。この利点の 1 つは、実行時にジェネリック型チェックがなくなり、コードの実行前にこれらのチェックが分離されるため、一連のパフォーマンスが向上することです。

しかし、これはすぐに PHP における単相ジェネリックの問題につながります。 PHP には、Rust のようにジェネリック クラスをいくつかの具体的な実装に分割するための明示的なコンパイル手順がありません; 結論としては、単相ジェネリックは同じクラスのコピーを複数作成するため、かなりの量のメモリを必要としますが、いくつかの違いがあります。これは、コンパイルされた Rust バイナリにとっては大きな問題ではないかもしれませんが、中央ポイント (サーバー) から実行される PHP コードにとっては深刻な問題であり、毎秒数百または数千のリクエストを処理する可能性があります。

次のオプションは、ジェネリックを具体化することです。ジェネリッククラスはそのままにして、実行時に型情報を動的に評価する実装です。 C# と Kotlin は、PHP が実行時にすべての型チェックを実行するため、PHP の現在の型システムに最も近いジェネリックスを実装します。ここでの問題は、実体化されたジェネリックスを機能させるために多くのコア コードのリファクタリングが必要であることです。実行時の型チェックが増えるにつれて、パフォーマンスのオーバーヘッドが徐々に増加することが想像できます。

これにより、最後のオプションが表示されます。実行時にジェネリックを完全に無視します。それらは存在しないようなものですが、結局のところ、たとえばコレクション クラスの汎用実装は、とにかくあらゆる種類の入力を処理できます。

したがって、実行時にジェネリック型チェックをすべて無視しても、問題はありません。

そうですね、それほど速くはありません。実行時にジェネリック型を無視すると (ちなみに、これは型消去と呼ばれ、Java と Python ではこれが行われます)、PHP にいくつかの問題が発生しました。

例を挙げてみましょう: PHP は検証に型を使用するだけでなく、型情報を使用して値をある型から別の型に動的に変換します - これは、このシリーズの最初の記事で説明したことです。問題点:

function add(int $a, int $b): int 
{
    return $a + $b;
}
add(&#39;1&#39;, &#39;2&#39;) // 3;

PHP がこの「文字列」コレクションのジェネリック型を無視し、誤って整数を追加した場合、ジェネリック型が削除された場合に警告が表示されません。私たち:

$slugs = new Collection<string>();
$slugs[] = 1; // 1 不会被转换为 &#39;1&#39;

型の消去に関する 2 番目の、そしてより重要な問題は、おそらく今まで画面に向かって叫んでいたことでしょうが、型が消えるということです。ジェネリック型が実行時に削除される場合、なぜ追加するのでしょうか?

Java と Pyton では、静的アナライザーでコードを実行する前にすべての型定義がチェックされるため、これは理にかなっています。たとえば、Java はコードをコンパイルするときに組み込みの静的アナライザーを実行しますが、PHP ではまったく実行しません。つまり、コンパイル手順がなく、もちろん組み込みの静的型チェッカーもありません。

一方...以前の記事で説明した型チェックの利点はすべて、PHP の組み込みランタイム型チェッカーから得られるものではありません。 PHP の型チェッカーが問題があることを示したとき、私たちはすでにコードを実行しています。型エラーは基本的にプログラムをクラッシュさせます。

代わりに、型チェックの付加価値のほとんどは、コードを実行する必要のない静的アナライザーから得られます。プログラマが十分な型情報を提供している限り、実行時の型エラーが発生しないことを保証できる可能性は十分にあります。これは、コード内にエラーが存在してはいけないという意味ではありませんが、完全に静的にチェックされ、実行時にいかなる種類のエラーも生成しない PHP コードを作成することは可能です。結論: コードを記述している間にすべての静的な洞察が得られます。これは、実行時の型チェックとは関係なく、あらゆる型システムの最も価値のある部分です。

では、実行時の型チェックは本当に必要なのでしょうか?これが、現在 PHP にジェネリックを追加できない主な理由であるためです。実行時にジェネリック型を検証することは、PHP にとって複雑すぎるか、リソースを大量に消費しすぎます。

元のアドレス: https://stitcher.io/blog/generics-in-php-3

翻訳アドレス: https://learnku.com/php/t/ 66486

推奨される学習: 「PHP ビデオ チュートリアル

以上がPHP でジェネリックが使用できない理由を分析してみましょうの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事はlearnku.comで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。