PHP Reflection: Wie kann man wissen, ob eine Methode / Eigenschaft / Konstante vom Merkmal geerbt wird?

9

Ich möchte alle geerbten Methoden von Merkmalen aus der Liste ausschließen, die in einer Klasse nicht überschrieben werden Wie kann man wissen, ob ein Klassenmitglied von einem Merkmal geerbt wurde?

Ja, ich kann es so überprüfen:

%Vor%

Aber was, wenn die Trait-Methode in einer Klasse überschrieben wird? Wie kann ich es wissen? Eine Möglichkeit besteht darin, zu prüfen, ob Methodenkörper ähnlich sind. Wenn ja, kann ich sie ausschließen, Aber gibt es einen besseren Weg, dies zu erreichen?

    
Tornike Comaia 05.06.2015, 08:38
quelle

3 Antworten

2

Wichtige Hinweise

Dies ist nur wegen des "akademischen" Interesses, in einer realen Situation, die Sie nicht interessieren sollten - von wo Methode abgeleitet wurde, wie es der Idee von Merkmalen widerspricht, z. transparente Substitution.

Auch wegen der Funktionsweise von Traits kann jede Art von Manipulation als "Hacky" betrachtet werden, daher kann sich das Verhalten bei verschiedenen PHP-Versionen unterscheiden und ich würde nicht empfehlen, darauf zu vertrauen.

Unterscheidung: Schwierigkeiten

In Reflektion für PHP gibt es Methoden getTraits() , die ReflectionClass Instanz, zeigt auf die Reflexion der Eigenschaft. Dies kann verwendet werden, um alle in Eigenschaften deklarierten Methoden abzurufen, die in der Klasse verwendet werden. Allerdings - nein, es hilft nicht in Ihrer Frage, da es nicht möglich sein wird, zu unterscheiden, welche Methoden dann in der Klasse außer Kraft gesetzt wurden.

Stellen Sie sich vor, dass es das Merkmal X mit den Methoden foo() und bar() gibt und die Klasse Z mit der Methode bar() . Dann können Sie wissen, dass die Methoden foo() und bar() im Merkmal deklariert sind, aber wenn Sie versuchen werden, getMethods() für die Klasse Z - Sie erhalten natürlich auch foo() und bar() . Daher können Sie den Fall nicht direkt unterscheiden.

Unterscheidung: work-around

Aber ja, es gibt einen Weg, es immer noch funktionieren zu lassen. Erster Weg - ist - wie du schon erwähnt hast - versuche Quellcode zu untersuchen. Es ist ziemlich hässlich, aber am Ende ist dies der einzige 100% zuverlässige Weg, um die Angelegenheit zu lösen.

Aber - nein, es gibt einen anderen, "weniger hässlichen" Weg - Instanzen auf ReflectionMethod Klassen, die für Klassen- / Merkmalsmethoden erstellt werden. Es kommt vor, dass PHP die gleiche Instanz für die Trait-Methode verwendet, aber die in der Klasse deklarierte Methode überschreibt.

Diese "Inspektion" kann mit spl_object_hash() durchgeführt werden. Einfache Einrichtung:

%Vor%

Und jetzt, um Hashes für beide Fälle zu holen:

%Vor%

Kurz gesagt: Es ruft nur alle Methoden aus dem Klassenmerkmal (erste Funktion) oder Klasse selbst (zweite Funktion) ab und führt dann die Ergebnisse zusammen, um key=>value map zu erhalten, wobei Schlüssel Objekt-Hash und Wert Methodenname ist.

Dann müssen wir das für dieselbe Instanz wie folgt verwenden:

%Vor%

Also wird $traitOnlyMethods nur die Methoden enthalten, die von der Eigenschaft abgeleitet sind.

Die entsprechende Geige ist hier . Aber achten Sie auf die Ergebnisse - sie können sich von Version zu Version unterscheiden, wie in HHVM funktioniert es einfach nicht (ich gehe davon aus, wie spl_object_hash implementiert ist - es ist also nicht sicher, ob es sich auf Objekte bezieht) Unterscheidung - siehe Dokumentation für die Funktion).

Also, TD; DR; - Ja, es kann (irgendwie) auch ohne Quellcode-Parsing gemacht werden - aber ich kann mir keinen Grund vorstellen, warum es benötigt wird, wie es Charakterzüge sein sollen verwendet, um Code in die Klasse zu ersetzen.

    
Alma Do 12.06.2015, 14:28
quelle
1

Es tut mir leid, aber die akzeptierte Antwort von Alma Do ist völlig falsch .

Diese Lösung funktioniert nicht , selbst wenn Sie das Problem der wiederverwendbaren Werte von spl_object_hash () überwinden. Dieses Problem kann behoben werden, indem die get*MethodRefs() -Funktionen in eine Funktion umgeformt werden, die beide Ergebnisse berechnet und sicherstellt, dass die ReflectionMethod -Objekte für die Merkmalmethoden noch vorhanden sind, wenn die analogen Objekte für die Klassenmethoden erstellt werden. Dies verhindert die Wiederverwendung von spl_object_hash () - Werten.

Das Problem ist, dass die Annahme, dass "PHP dieselbe Instanz für die Trait-Methode verwenden wird" völlig falsch ist, und das Auftreten dieses Ereignisses genau aus "glücklicher" spl_object_hash () - Wiederverwertung resultiert. Das von $traitRef->getMethod('someName') zurückgegebene Objekt unterscheidet sich von immer von dem von $classRef->getMethod('someName') zurückgegebenen Objekt. Dies gilt auch für die entsprechenden Instanzen von ReflectionMethod in Sammlungen, die von ->getMethods() zurückgegeben werden, unabhängig von ob die Methode someName() in der Klasse überschrieben wird oder nicht Diese Objekte sind nicht nur verschieden, sie sind auch nicht "gleich": Die ReflectionMethod Instanz, die von $traitRef erhalten wird, hat den Namen des Merkmals als Wert seiner class Eigenschaft, und den von erhalten $classRef hat dort den Namen der Klasse.

Geige: Ссылка

Es scheint, dass nur Parser-basierte Ansätze dann praktikabel sind.

    
Szczepan Hołyszewski 14.12.2016 21:42
quelle
1

Eine einfachere Methode ist ReflectionMethod::getFileName() . Dadurch wird der Dateiname des Merkmals zurückgegeben, nicht die Klasse.

Für den exotischen Fall, in dem Merkmal und Klasse in derselben Datei sind, kann man ReflectionMethod::getStartLine() verwenden und dies mit der Start- und Endlinie des Merkmals und der Klasse vergleichen.

Für den exotischen Fall, in dem die Eigenschaften, die Klasse und die Methode auf derselben Linie sind ... oh bitte!

    
donquixote 28.08.2017 06:27
quelle

Tags und Links