Schauen wir uns zunächst ein typisches Beispiel an. Um sicherzustellen, dass der Dienst einer bestimmten Schnittstelle entspricht, verwenden Entwickler, um sicherzustellen, dass der Dienst eine bestimmte Schnittstelle entspricht, ähnlich wie folgt:
<Code> if (! is_a ($ serviceInstance, myServiceInterface :: class)) {neue InvalidArgumentException ("Service muss myServiceInterface implementiert"); } </code>Auf der Oberfläche verhindert dies die Injektion von Fehlertypen während der Registrierungsphase, wodurch die Laufzeitfehler vermieden werden. In der Tat ist dieser Ansatz eine Garantie für die Schnittstellenisolation. Aber hier ist die Frage: Ist es wirklich notwendig, manuell zu überprüfen?
Ausgehend von Php 7 ist die Eingabeaufforderung leistungsstark genug:
<Code> Funktion Regierservice (MyServiceInterface $ Service) {// ...} </code>Wenn Sie zu diesem Zeitpunkt in einer Instanz bestehen, die nicht mit dem MyServiceInterface übereinstimmt, wirft PHP selbst ein Typeerror . Müssen wir es also noch einmal mit is_a () manuell überprüfen?
Eigentlich ist es nicht notwendig. Sofern Ihr Code nicht zulässt, dass gemischte Typen übergeben werden, oder die Quelle der Serviceinstanz sehr ungewiss ist (z. B. eine Remote-Instanzinjektion, ein Plug-in-Systembelastung usw.), ist der PHP-Eingabeaufforderungsmechanismus ausreichend.
Die Überbeanspruchung von IS_A () bringt einige versteckte Probleme mit sich:
Wiederholte Überprüfung : Das Typsystem wurde überprüft und es wird manuell wiederholt, um die Wartungsbelastung zu erhöhen.
Hindernispolymorphismus : Einige Implementierungsklassen können Instanzen mit Merkmalen oder dynamischen Proxy -Methoden generieren, und die Überprüfung von IS_A () kann dazu führen, dass es als illegales Objekt falsch eingeschätzt wird.
Machen Sie Container Logik überflüssig : Die Verantwortung eines Containers besteht darin, Abhängigkeiten zu analysieren und zu injizieren, anstatt die Überprüfung der Typen zu erzwingen. Zu schwere Verantwortung kann leicht zu einer Kopplung führen.
Es bedeutet nicht, dass is_a () nutzlos ist. Es ist in den folgenden Szenarien immer noch nützlich:
Plugin -System: Wenn die erweiterte Klasse, die von einem Dritten bereitgestellt wird, nicht mit den Typ -Eingabeaufforderungen eingeschränkt werden kann, kann die Verwendung von IS_A () im Voraus fehlschlagen.
Dynamische Dienstregistrierung: Wenn Sie beispielsweise eine Konfigurationsdatei zum dynamischen Sofizieren des Dienstes lesen, ist die entsprechende IS_A () -Verifizierung aus Sicherheitsgründen akzeptabel.
Vermeiden Sie böswillige Injektion: In großen Systemen können einige Module von mehreren Teams aufrechterhalten werden, und die Verwendung von IS_A (), da die endgültige Verteidigungsstrategie auch eine Bottom-up-Strategie ist.
In der normalen Serviceregistrierungslogik wird empfohlen, nach Möglichkeit den nativen Eingabeaufforderung der nativen Art zu verwenden + automatische Abhängigkeitsinjektion. Halten Sie den Code einfach und die Verantwortlichkeiten Single. Bei Behältern reicht es aus, Objekte zu konstruieren, Abhängigkeiten zu injizieren und Lebenszyklen zu lösen, und es besteht keine Notwendigkeit, die Verantwortung für die "Überprüfung der Polizei" zu übernehmen .
Wenn eine dynamische Überprüfung wirklich erforderlich ist, wird empfohlen, IS_A () in eine Werkzeugfunktion einzubeziehen und auf einheitliche Weise zu verwalten, z. B.:
<Code> Funktion assertImplements ($ Instance, String $ Schnittstelle) {if (! is_a ($ instance, $ interface)) {thrown InvalidArgumentException ("Instanz nicht implementiert: $ interface"); }} </code>Dies verbessert nicht nur die Lesbarkeit, sondern reduziert auch die Kopplung.