Wie überprüfe ich die Klasse eines Objekts in der Umgebung mit PHP-Namensabständen, ohne die vollständige Klasse mit Namensabständen anzugeben?
Angenommen, ich hätte eine Objektbibliothek / Entität / Vertrag / Name.
Der folgende Code funktioniert nicht, da get_class die vollständige Namespace-Klasse zurückgibt.
If(get_class($object) == 'Name') {
... do this ...
}
Das Namespace Magic-Schlüsselwort gibt den aktuellen Namespace zurück. Dies ist nicht sinnvoll, wenn das getestete Objekt einen anderen Namespace hat.
Ich könnte einfach den vollständigen Klassennamen mit Namespaces angeben, aber dies scheint die Struktur des Codes zu blockieren. Auch nicht sehr nützlich, wenn ich den Namespace dynamisch ändern wollte.
Kann sich jemand einen effizienten Weg vorstellen, dies zu tun. Ich denke, eine Option ist Regex.
quelle
Antworten:
Sie können dies mit Reflexion tun. Insbesondere können Sie die verwenden
ReflectionClass::getShortName
Methode verwenden, die den Namen der Klasse ohne ihren Namespace abruft.Zuerst müssen Sie eine
ReflectionClass
Instanz erstellen und dann diegetShortName
Methode dieser Instanz aufrufen :Ich kann mir jedoch nicht viele Umstände vorstellen, unter denen dies wünschenswert wäre. Wenn Sie möchten, dass das Objekt Mitglied einer bestimmten Klasse ist, können Sie es mit testen
instanceof
. Wenn Sie eine flexiblere Methode zum Signalisieren bestimmter Einschränkungen wünschen, müssen Sie dazu eine Schnittstelle schreiben und verlangen, dass der Code diese Schnittstelle implementiert. Auch hier ist der richtige Weg, dies zu tuninstanceof
. (Sie können es damit machenReflectionClass
, aber es hätte eine viel schlechtere Leistung.)quelle
Tenant
im aktuellen Namespace nicht vorhanden. Versuchen Sie esvar_dump($tenant instanceof \Library\Entity\People\Tenant)
stattdessen. Untersuchen Sie auch die Verwendung desuse
Operators und das allgemeine Konzept hinter PHP-Namespaces!$reflect = new \ReflectionClass($object);
str_replace(__NAMESPACE__ . '\\', '', __CLASS__);
. Es ist auch viel schneller, was die Leistung betrifft.(new \ReflectionClass($obj))->getShortName();
ist die beste Lösung in Bezug auf die Leistung.Ich war neugierig, welche der angebotenen Lösungen die schnellste ist, deshalb habe ich einen kleinen Test zusammengestellt.
Ergebnisse
Code
Die Ergebnisse haben mich tatsächlich überrascht. Ich dachte, die Explosionslösung wäre der schnellste Weg ...
quelle
Ich habe dem Test von https://stackoverflow.com/a/25472778/2386943 substr hinzugefügt, und so konnte ich (CentOS PHP 5.3.3, Ubuntu PHP 5.5.9) beide mit einem i5 testen.
Ergebnisse
Code
== UPDATE ==
Wie in den Kommentaren von @MrBandersnatch erwähnt, gibt es noch einen schnelleren Weg, dies zu tun:
Hier sind die aktualisierten Testergebnisse mit "SubstringStrChr" (spart bis zu 0,001 s):
quelle
str_replace(__NAMESPACE__ . '\\', '', __CLASS__);
. Die Ergebnisse auf einer schwachen virtuellen Maschine zeigten, dass sie fast doppelt so schnell ist wie alle diese.php -f bench.php Reflection: 0.44037771224976 s ClassA Basename: 0.48089025020599 s ClassA Explode: 0.54955270290375 s ClassA Substring: 0.38200764656067 s ClassA Frank's Custom Benchmark: 0.22782742977142 s ClassA
if ($pos = strrchr(static::class, '\\')) { .. } else { ... }
.$classNameShort = substr(strrchr('\\' . get_class($this), '\\'), 1);
Dies ist eine einfachere Möglichkeit, wenn Sie das Laravel PHP-Framework verwenden:
quelle
Ich benutze das:
quelle
So erhalten Sie den Kurznamen als Einzeiler (seit PHP 5.4 ):
Es ist ein sauberer Ansatz und vernünftig schnell .
quelle
Ich befand mich in einer einzigartigen Situation, in der ich
instanceof
nicht verwendet werden konnte (insbesondere Merkmale mit Namensraum), und ich brauchte den Kurznamen so effizient wie möglich, sodass ich selbst einen kleinen Benchmark erstellt habe. Es enthält alle verschiedenen Methoden und Variationen der Antworten in dieser Frage.Eine Liste des gesamten Ergebnisses finden Sie hier, aber hier sind die Highlights:
$obj->getShortName()
ist die schnellste Methode jedoch ; Es ist fast die langsamste Methode , Reflexion nur zu verwenden, um den Kurznamen zu erhalten.'strrpos'
kann einen falschen Wert zurückgeben, wenn sich das Objekt nicht in einem Namespace befindet'safe strrpos'
befindet. es also etwas langsamer ist, würde ich sagen, dass dies der Gewinner ist.'basename'
Kompatibilität zwischen Linux und Windows zu gewährleisten, müssen Sie diese verwendenstr_replace()
, wodurch diese Methode die langsamste von allen ist.In einer vereinfachten Ergebnistabelle wird die Geschwindigkeit im Vergleich zur langsamsten Methode gemessen:
quelle
Sie können
explode
den Namespace trennen undend
den Klassennamen abrufen:quelle
Yii Weg
Yii verwendet diese Methode in seinem Gii-Codegenerator
Methodendokumentation
Mehr Informationen:
https://github.com/yiisoft/yii2/blob/master/framework/helpers/BaseStringHelper.php http://www.yiiframework.com/doc-2.0/yii-helpers-basestringhelper.html#basename()-detail
quelle
Hier ist eine einfache Lösung für PHP 5.4+
Was wird zurückgegeben?
Der erweiterte Klassenname und der erweiterte Namespace eignen sich gut für:
Was ist mit der Klasse im globalen Namespace?
quelle
Wenn Sie den Klassennamen kennen müssen, der innerhalb einer Klasse aufgerufen wurde, und den Namespace nicht möchten, können Sie diesen verwenden
Dies ist ideal, wenn Sie eine Methode in einer Klasse haben, die um andere Klassen erweitert wird. Darüber hinaus funktioniert dies auch, wenn Namespaces überhaupt nicht verwendet werden.
Beispiel:
quelle
Basierend auf der Antwort von @MaBi habe ich Folgendes gemacht:
Was Sie so verwenden können:
A::class
kehrt zurückFoo\Bar\Baz\A
,A::getClassShortName()
kehrt aber zurückA
.Funktioniert für PHP> = 5.5.
quelle
Ich weiß, dass dies ein alter Beitrag ist, aber das ist, was ich benutze - Schneller als alle oben genannten, rufen Sie einfach diese Methode aus Ihrer Klasse auf, viel schneller als mit Reflection
quelle
Gefunden auf der Dokumentationsseite von get_class , wo es von mir bei nwhiting dot com gepostet wurde .
Die Idee von Namespaces ist jedoch, Ihren Code zu strukturieren. Das bedeutet auch, dass Sie Klassen mit demselben Namen in mehreren Namespaces haben können. Theoretisch könnte das Objekt, das Sie übergeben, den Klassennamen name (stripped) haben und dennoch ein völlig anderes Objekt sein als erwartet.
Außerdem möchten Sie möglicherweise nach einer bestimmten Basisklasse suchen . In diesem Fall
get_class
reicht der Trick überhaupt nicht aus. Vielleicht möchten Sie den Operator überprüfeninstanceof
.quelle
Möglicherweise erhalten Sie ein unerwartetes Ergebnis, wenn die Klasse keinen Namespace hat. Dh
get_class
kehrtFoo
, dann$baseClass
wäreoo
.Dies kann leicht behoben werden, indem
get_class
ein Backslash vorangestellt wird :Jetzt geben auch Klassen ohne Namespace den richtigen Wert zurück.
quelle
Ein guter alter Regex scheint schneller zu sein als die meisten der zuvor gezeigten Methoden:
Dies funktioniert also auch, wenn Sie einen kurzen Klassennamen oder einen vollständig qualifizierten (kanonischen) Klassennamen angeben.
Der Regex verbraucht alle vorherigen Zeichen, bis das letzte Trennzeichen gefunden wird (das auch verbraucht wird). Die verbleibende Zeichenfolge ist also der kurze Klassenname.
Wenn Sie ein anderes Trennzeichen verwenden möchten (z. B. /), verwenden Sie stattdessen einfach dieses Trennzeichen. Denken Sie daran, den Backslash (dh. \) Und auch das Musterzeichen (dh. /) Im Eingabemuster zu umgehen.
quelle
Da "ReflectionClass" versionabhängig sein kann, verwenden Sie einfach Folgendes:
oder sogar klar
quelle
Zitieren von php.net:
Basierend auf diesen Informationen und der Erweiterung von arzzzen answer sollte dies sowohl auf Windows- als auch auf Nix * -Systemen funktionieren:
Hinweis: Ich habe einen Benchmark von
ReflectionClass
gegenbasename+str_replace+get_class
und Reflexion durchgeführt, der ungefähr 20% schneller ist als der Basisnamen-Ansatz, aber YMMV.quelle
Die schnellste und einfachste Lösung, die in jeder Umgebung funktioniert, ist:
quelle
$Object->__class->getShortName()
mich über PHP wirklich wütend. Ihr Ansatz funktioniert, aber jetzt setzen Sie konkrete Methoden in Ihre Klassen ein, um aufzudecken, was ein Sprachkonstrukt sein sollte.quelle
Wenn Sie nur Namensräume entfernen und nach dem letzten \ in einem Klassennamen mit Namespace etwas möchten (oder nur den Namen, wenn kein '\' vorhanden ist), können Sie Folgendes tun:
Grundsätzlich ist es Regex, eine beliebige Kombination von Zeichen oder Backslashes zu erhalten und bis zum letzten Backslash nur die Nicht-Backslash-Zeichen bis zum Ende der Zeichenfolge zurückzugeben. Hinzufügen der? Wenn nach der ersten Gruppierung die Musterübereinstimmung nicht vorhanden ist, wird nur die vollständige Zeichenfolge zurückgegeben.
quelle
Am schnellsten habe ich hier für
PHP 7.2
am gefundenUbubntu 18.04
quelle