Dieser Artikel vermittelt Ihnen ein tiefgreifendes Verständnis der Generika in PHP und stellt zwei generische Beispiele vor. Ich hoffe, er wird Ihnen hilfreich sein!
Ich habe in meinem vorherigen Beitrag ein sehr langweiliges Beispiel für Generika gezeigt und in diesem werden wir es besser machen.
$users = new Collection<User>(); $slugs = new Collection<string>();
Sammlungen
Sie sind wahrscheinlich die einfachste Möglichkeit, Generika zu erklären, aber sie sind auch die Beispiele, über die jeder spricht, wenn es um Generika geht. Oft werden „Generika“ und „typisierte Sammlungen“ als dasselbe betrachtet. Absolut nicht der Fall. 集合
它们可能是解释泛型的最简单方法,但它们也是每个人在讨论泛型时都会谈论的示例。人们通常认为「泛型」和「具有类型的集合」是一回事。绝对不是这样。
所以让我们再看两个例子。
这是一个名为「app」的函数——如果你使用像 Laravel 这样的框架,它可能看起来很熟悉:这个函数接受一个类名,并使用依赖容器解析该类的一个实例:
function app(string $className): mixed { return Container::get($className); }
现在,你不需要知道容器是如何工作的,重要的是这个函数会给你一个你请求的类的实例。
所以,基本上,它是一个通用函数;一个返回类型取决于你给它的类名。如果我们的 IDE 和其他静态分析器也明白,如果我给这个函数提供类名「UserRepository」,我希望返回一个 UserRepository 的实例,而不是别的,那就太酷了:
function app(string $className): mixed { /* … */ } app(UserRepository::class); // ?
好吧,泛型允许我们这样做。
我想现在是提一下我一直保守秘密的好时机,就像: 我在 上一篇 中提到 PHP 中不存在泛型;好吧,这并不完全正确。那里的所有静态分析器——无需运行即可读取代码的工具,像你的 IDE 之类的工具——他们允许将 doc 块注释用于泛型:
/** * @template Type * @param class-string<Type> $className * @return Type */ function app(string $className): mixed { /* … */ }
诚然:这不是最完美的语法,所有静态分析器都依赖于一个简单的协议,即这是没有官方规范语法; 但是:它有效。PHP 世界中最大的三个静态分析器:PhpStorm、Psalm 和 PhpStan,都在一定程度上理解这种语法。
像 PhpStorm 这样的 IDE 使用它,以便在程序员编写代码时向他们提供反馈,而像 Psalm 和 PhpStan 这样的工具使用它,来批量分析你的代码库并检测潜在的 bug,主要基于类型定义。
所以实际上,我们可以构建这个 app
函数,使我们的工具不再在黑暗中运行。 当然,PHP 本身并不能保证返回类型是正确的,因为 PHP 不会在运行时对该函数进行类型检查; 但是,如果我们可以相信我们的静态分析器是正确的,那么在运行它时,这段代码就很少——甚至没有机会被中断。
这就是静态分析令人难以置信的力量:实际上,我们可以确定,无需运行我们的代码; 其中大部分将按预期工作。 所有这一切都归功于类型——包括泛型。
让我们来看一个更复杂的例子:
Attributes::in(MyController::class) ->filter(RouteAttribute::class) ->newInstance() ->
在这里,我们有一个可以“查询”属性并即时实例化它们的类。 如果你在知道它们的反射 API 相当冗长之前使用过属性,那么我发现这种辅助类非常有用。
当我们使用 filter
方法时,我们给它一个属性的类名; 然后调用 newInstance
/** @template AttributeType */ class Attributes { /** * @template InputType * @param class-string<InputType> $className * @return self<InputType> */ public function filter(string $className): self { /* … */ } /** * @return AttributeType */ public function newInstance(): mixed { /* … */ } // … }
rrreee
Okay, das generische Kata ermöglicht uns das . 🎜🎜 Ich dachte, jetzt wäre ein guter Zeitpunkt, ein Geheimnis zu erwähnen, das ich geheim gehalten habe, wie zum Beispiel: Ich habe in meinem vorherigen Beitrag erwähnt, dass es in PHP keine Generika gibt, das stimmt nicht ganz. Alle statischen Analysatoren da draußen – Tools, die Code lesen, ohne ihn auszuführen, Tools wie Ihre IDE – ermöglichen die Verwendung von Dokumentblockkommentaren für Generika: 🎜rrreee🎜 Zugegeben: nicht die perfekteste Syntax, alle statischen Analysatoren basieren auf einem einfachen Protokoll , das heißt, es gibt keine offizielle kanonische Syntax: Es funktioniert. Drei der größten statischen Analysatoren in der PHP-Welt: PhpStorm, Psalm und PhpStan, alle verstehen diese Syntax bis zu einem gewissen Grad. 🎜🎜IDEs wie PhpStorm verwenden es, um Programmierern beim Schreiben von Code Feedback zu geben, während Tools wie Psalm und PhpStan es verwenden, um Ihre Codebasis massenhaft zu analysieren und potenzielle Fehler zu erkennen, hauptsächlich basierend auf Typdefinitionen. 🎜🎜Tatsächlich können wir dieseapp
-Funktion so erstellen, dass unser Tool nicht mehr im Dunkeln läuft. Natürlich kann PHP selbst nicht garantieren, dass der Rückgabetyp korrekt ist, da PHP die Funktion zur Laufzeit nicht auf Typ überprüft. Wenn wir jedoch darauf vertrauen können, dass unser statischer Analysator korrekt ist, gibt es in diesem Absatz nur sehr wenig Code - keine Chance auf Unterbrechung. 🎜🎜Das ist die unglaubliche Leistungsfähigkeit der statischen Analyse: Wir können tatsächlich sicher sein, dass das meiste davon wie erwartet funktioniert. All dies ist dank Typen – einschließlich Generika – möglich. 🎜🎜Sehen wir uns ein komplexeres Beispiel an: 🎜rrreee🎜Hier haben wir eine Klasse, die Eigenschaften „abfragen“ und sie im laufenden Betrieb instanziieren kann. Ich finde diese Hilfsklasse sehr nützlich, wenn Sie Eigenschaften verwendet haben, bevor Sie wussten, dass ihre Reflexions-API ziemlich ausführlich ist. 🎜🎜Wenn wir die Methode filter
verwenden, geben wir ihr den Klassennamen einer Eigenschaft und rufen dann die Methode newInstance
auf, da wir wissen, dass das Ergebnis eine Instanz von uns sein wird Filterklasse. Nochmals: Es wäre großartig, wenn unsere IDE verstehen würde, wovon wir sprechen. 🎜🎜Sie haben es erraten: Generika ermöglichen uns Folgendes: 🎜rrreee🎜 Ich hoffe, Sie beginnen, die Macht einfacher Typinformationen zu erkennen. Vor ein paar Jahren brauchte ich ein IDE-Plugin, damit diese Erkenntnisse funktionieren, jetzt muss ich nur noch ein paar Typinformationen hinzufügen. 🎜🎜Dieses neueste Beispiel basiert jedoch nicht nur auf Generika, es spielt noch eine weitere, ebenso wichtige Rolle eine Rolle. Typinferenz: Die Fähigkeit eines statischen Analysators, Typen zu „erraten“ oder zuverlässig zu bestimmen, ohne dass der Benutzer sie angibt. Das ist es, was dort mit der stringartigen Annotation passiert. Unsere IDE ist in der Lage, die Eingabe, die wir dieser Funktion bereitstellen, als Klassennamen zu erkennen und den Typ als generischen Typ abzuleiten. 🎜🎜Also, es ist alles geklärt, richtig: Es gibt Generika in PHP und alle großen statischen Analysatoren wissen, wie man sie verwendet. Nun... es gibt ein paar Vorbehalte. 🎜🎜Erstens gibt es keine offizielle Spezifikation, wie Generika aussehen sollten. Derzeit kann jeder statische Analysator seine eigene Syntax verwenden, aber die Zukunft ist kaum garantiert. 🎜Zweitens: Dokumentblöcke sind meiner Meinung nach suboptimal. Sie fühlen sich in unserer Codebasis weniger wichtig an. Natürlich bieten generische Annotationen nur statische Einblicke und keine Laufzeitfunktionalität, aber wir haben die Leistungsfähigkeit der statischen Analyse auch ohne Laufzeittypprüfung gesehen. Ich halte es für unfair, Typinformationen als „Dokumentationskommentare“ zu betrachten, da sie nicht die Bedeutung dieser Typen in unserem Code vermitteln. Aus diesem Grund haben wir in PHP8 Attribute eingeführt: Die gesamte durch Attribute bereitgestellte Funktionalität war in Docblock-Kommentaren möglich, aber es fühlte sich einfach nicht gut genug an. Das Gleiche gilt für Generika.
Abschlussbemerkung: Ohne ordnungsgemäße Spezifikation weisen alle drei großen statischen Analysatoren Unterschiede zwischen ihren generischen Implementierungen auf. PHPStorm ist derzeit das am meisten vermisste Programm. Idealerweise gäbe es eine offizielle Spezifikation innerhalb von PHP. Aber es gibt noch kein offizielles.
Das sind die Hauptgründe, warum es sich meiner Meinung nach lohnt, Zeit in längerfristige, nachhaltigere Lösungen zu investieren. Warum verfügt PHP noch nicht über die richtigen Generika? Warum verlassen wir uns auf Dokumentationsblöcke ohne klare Spezifikation?
Originaladresse: https://stitcher.io/blog/generics-in-php-2
Übersetzungsadresse: https://learnku.com/php/t/66484
Empfohlen: „PHP-Video Tutorial》
Das obige ist der detaillierte Inhalt vonErfahren Sie anhand von Beispielen mehr über Generika in PHP. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!