Wie erhalte ich den nicht qualifizierten (kurzen) Klassennamen eines Objekts?
Lesezeit: 12 Minuten
Greg. Forbes
Wie überprüfe ich die Klasse eines Objekts innerhalb der PHP-Namespace-Umgebung, ohne die vollständige Namespace-Klasse anzugeben?
Nehmen wir zum Beispiel an, 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 magische Schlüsselwort namespace gibt den aktuellen Namespace zurück, was sinnlos ist, wenn das getestete Objekt einen anderen Namespace hat.
Ich könnte einfach den vollständigen Klassennamen mit Namensräumen angeben, aber dies scheint die Struktur des Codes einzuschließen. Auch nicht von großem Nutzen, wenn ich den Namensraum dynamisch ändern wollte.
Kann sich jemand einen effizienten Weg vorstellen, dies zu tun. Ich denke, eine Option ist Regex.
Es erscheint nahezu sinnlos, da in verschiedenen Namespaces dieselben Klassennamen definiert sein könnten. Wie werden Sie also damit umgehen? Und das liegt daran, dass der vollqualifizierte Klassenname in Ihrem Beispiel zurückgegeben wird
– Alma tun
11. November 2013 um 8:30 Uhr
Ich bin auf einem mobilen Gerät, daher kann ich keine anständige Antwort senden, aber die Lösung ist Reflektion, insbesondere ReflectionClass::getShortName – php.net/manual/en/reflectionclass.getshortname.php
– einsamer Tag
11. November 2013 um 8:55 Uhr
Für Leute, die nach einem Grund suchen, dies zu wollen: Es könnte in einer Hilfsfunktion in einer gemeinsamen Basisklasse nützlich sein (dh mehrere Namespaces sind in dieser Situation nie ein Problem).
– Darren Cook
16. Dezember 2013 um 9:05 Uhr
eines Tages
Sie können dies mit Reflexion tun. Insbesondere können Sie die verwenden ReflectionClass::getShortName -Methode, die den Namen der Klasse ohne ihren Namensraum erhält.
Zuerst müssen Sie eine erstellen ReflectionClass Instanz, und rufen Sie dann die auf getShortName Methode dieser Instanz:
$reflect = new ReflectionClass($object);
if ($reflect->getShortName() === 'Name') {
// do this
}
Ich kann mir jedoch nicht viele Umstände vorstellen, in denen dies wünschenswert wäre. Wenn Sie verlangen möchten, dass das Objekt Mitglied einer bestimmten Klasse ist, können Sie es mit testen instanceof. Wenn Sie bestimmte Einschränkungen flexibler signalisieren möchten, können Sie eine Schnittstelle schreiben und verlangen, dass der Code diese Schnittstelle implementiert. Auch hier ist der richtige Weg, dies zu tun, mit instanceof. (Sie können es mit ReflectionClassaber es hätte eine viel schlechtere Leistung.)
@Greg.Forbes Weil Tenant existiert nicht im aktuellen Namensraum. Versuchen var_dump($tenant instanceof \Library\Entity\People\Tenant) stattdessen. Untersuchen Sie auch, wie Sie die verwenden use -Operator und das allgemeine Konzept hinter PHP-Namespaces!
– einsamer Tag
13. November 2013 um 8:25 Uhr
Ich musste so einen Schrägstrich voranstellen $reflect = new \ReflectionClass($object);
– Programmhammer
12. März 2014 um 1:19 Uhr
Ich mache im Allgemeinen nicht gerne viel ReflectionClass-Voodoo in meiner Anwendung, da dies bei Missbrauch zu unerwarteten Ergebnissen führen kann (geschützte Methoden werden öffentlich usw.). Sie können stattdessen eine einfache String-Ersetzung für magische PHP-Konstanten verwenden: str_replace(__NAMESPACE__ . '\\', '', __CLASS__);. Es ist auch viel schneller, was die Leistung betrifft.
– Franklin P. Strube
11. November 2015 um 23:24 Uhr
@FranklinPStrube Sofern mir nichts fehlt, erhält das den Kurznamen der aktuellen Klasse und nicht die Klasse des Objekts. Ich stimme zu, dass die Verwendung von Reflexion normalerweise bedeutet, dass Sie es falsch machen.
– einsamer Tag
13. November 2015 um 18:16 Uhr
Viele Leute verwenden Reflections zum Überschreiben der Sichtbarkeit von Mitgliedern, was SCHLECHT ist. TU das nicht! Aber zu sagen, dass die Verwendung von Reflections im Allgemeinen Voodoo und Doing It Wrong ist, gibt den Leuten einen falschen Eindruck. Man sollte ihnen nicht aus dem Weg gehen, man sollte sie verstehen und wissen, wann sie auf welcher Abstraktionsebene förderlich sind.
–Vanja D.
19. April 2018 um 11:34 Uhr
Hirnhamster
(new \ReflectionClass($obj))->getShortName(); ist die beste Lösung in Bezug auf die Leistung.
Ich war neugierig, welche der bereitgestellten Lösungen die schnellste ist, also habe ich einen kleinen Test zusammengestellt.
Ergebnisse
Reflection: 1.967512512207 s ClassA
Basename: 2.6840535163879 s ClassA
Explode: 2.6507515668869 s ClassA
Die Ergebnisse haben mich tatsächlich überrascht. Ich dachte, die Explosionslösung wäre der schnellste Weg …
Gute Antwort. Ich habe denselben Code ausgeführt, aber ich habe ein anderes Ergebnis erhalten (Macbook Pro i7, 16 GB RAM). Reflexion:0,382, Basisname:0,380, Explosion:0,399. Ich denke, es hängt von Ihrem System ab, was am besten ist …
– Tobias Nyholm
2. Oktober 2014 um 9:49 Uhr
Führen Sie PHP 10.000 Mal mit diesem Code aus und Sie erhalten ein besseres Ergebnis. Das Obige kann die Reflexion aus einem Pool abrufen, aber dies ist nicht das übliche Verhalten der Anwendungen da draußen. Sie brauchen es nur ein- oder zweimal.
– LeMike
5. November 2014 um 11:21 Uhr
Ich frage mich, ob dieser Test zutrifft, wenn eine ReflectionClass für ein umfangreicheres Objekt als das kleine Objekt der Klasse A in Ihrem Test instanziiert wird …
– Joe Grün
16. Dezember 2014 um 14:48 Uhr
Wenn Sie nur eine Iteration anstelle von 100000 ausführen, erhalten Sie ein ganz anderes Ergebnis: Reflexion: 1,0967254638672 100000stel/s ClassA Basisname: 0,81062316894531 100000stel/s ClassA Explosion: 0,50067901611328 100000stel/s ClassA
– McMurphy
14. August 2018 um 21:56 Uhr
explode(‘\\’, static::class)[0] ? gibt es nicht den ersten Teil des Namensraums zurück? sollte den letzten Teil zurückgeben, nicht den ersten
– 2oppin
17. Oktober 2019 um 9:46 Uhr
MaBi
Ich habe substr zum Test von https://stackoverflow.com/a/25472778/2386943 hinzugefügt und das ist der schnellste Weg, den ich testen konnte (CentOS PHP 5.3.3, Ubuntu PHP 5.5.9), beide mit einem i5.
Hier die aktualisierten Testergebnisse mit “SubstringStrChr” (spart bis ca. 0,001 s):
Reflection: 0.073065280914307 s ClassA
Basename: 0.12585079669952 s ClassA
Explode: 0.14593172073364 s ClassA
Substring: 0.060415267944336 s ClassA
SubstringStrChr: 0.059880912303925 s ClassA
Nur weil wir aus Effizienzgründen auflisten, fand ich dies am schnellsten, Vergleich mit dem in dieser Lösung bereitgestellten Test substr(strrchr(get_class($obj), ‘\\’), 1); Reflexion: 0,084223914146423 s ClassA — Basename: 0,13206427097321 s ClassA — Explosion: 0,15331919193268 s ClassA — Substring: 0,068068099021912 s ClassA — Strrchar: 0,064720282 s ClassA –283
– ctatro85
6. Oktober 2015 um 14:55 Uhr
Ich bin gerade auf diesen Thread gestoßen und habe einen zusätzlichen Benchmark zum Testen hinzugefügt str_replace(__NAMESPACE__ . '\\', '', __CLASS__);. Die Ergebnisse auf einer schwachen virtuellen Maschine zeigten, dass sie fast doppelt so schnell war 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
– Franklin P. Strube
11. November 2015 um 23:20 Uhr
@MrBandersnatch Sie haben Recht. Ich habe Ihre Lösung getestet und sie hat mir etwa 0,001 s gespart. Ich habe meine Antwort mit Ihrer aktualisiert!
– MaBi
12. November 2015 um 21:39 Uhr
Warnung: Dieser Code funktioniert nicht mit Klassen im globalen Namensraum (dh: ihr vollständiger Name ist gleich ihrem Kurznamen)! Ich rate, etwas zu testen wie: if ($pos = strrchr(static::class, '\\')) { .. } else { ... }.
– Tristan Jahier
31. Mai 2016 um 15:57 Uhr
Damit es auch im globalen Namensraum funktioniert, stellen Sie dem Klassennamen einfach einen umgekehrten Schrägstrich voran 🙂 – dh: $classNameShort = substr(strrchr('\\' . get_class($this), '\\'), 1);
– rosell.dk
26. März 2019 um 8:40 Uhr
spetsnaz
Hier ist eine einfachere Möglichkeit, dies zu tun, wenn Sie das Laravel PHP-Framework verwenden:
<?php
// usage anywhere
// returns HelloWorld
$name = class_basename('Path\To\YourClass\HelloWorld');
// usage inside a class
// returns HelloWorld
$name = class_basename(__CLASS__);
/**
* Get the class "basename" of the given object / class.
*
* @param string|object $class
* @return string
*/
function class_basename($class)
{
$class = is_object($class) ? get_class($class) : $class;
return basename(str_replace('\\', "https://stackoverflow.com/", $class));
}
Sie können auch versuchen: $className = explode(‘\\’, basename(get_class($this))); $className = array_pop($className); um den einfachen Klassennamen zu erhalten. Oder verwenden Sie substr.
– dompie
25. Februar 2014 um 10:24 Uhr
Funktioniert nur unter Windows Unter Windows werden sowohl Schrägstrich (/) als auch umgekehrter Schrägstrich () als Verzeichnistrennzeichen verwendet. In anderen Umgebungen ist es der Schrägstrich (/) php.net/manual/en/function.basename.php
– OzzyCzech
28. Februar 2014 um 12:06 Uhr
Ich habe es jetzt behoben. Danke, @OzzyCzech.
– Theodore R. Smith
30. Dezember 2014 um 5:48 Uhr
@OzzyCzech Ich bin gerade darauf gestoßen, als ich von Windows zu Ubuntu gewechselt bin … zum Verrücktwerden. Aufgewickelt mit der in MaBis Update erwähnten Lösung.
– Chris Baker
14. Dezember 2015 um 16:20 Uhr
@OzzyCzech Wie kommt es, dass es nur unter Windows funktioniert? Die Frage bezog sich auf den vollqualifizierten Namespace-Namen, wenn ich mich auch vor Jahren nicht irre, und Namespaces sind nicht betriebssystemspezifisch und immer mit einem umgekehrten Schrägstrich wie Windows-Verzeichnistrennzeichen.
– FantomX1
13. Mai 2020 um 15:09 Uhr
Gemeinschaft
Um den Kurznamen als Einzeiler zu erhalten (seit PHP5.4):
echo (new ReflectionClass($obj))->getShortName();
Es ist ein sauberer Ansatz und angemessen schnell.
Sie können auch versuchen: $className = explode(‘\\’, basename(get_class($this))); $className = array_pop($className); um den einfachen Klassennamen zu erhalten. Oder verwenden Sie substr.
– dompie
25. Februar 2014 um 10:24 Uhr
Funktioniert nur unter Windows Unter Windows werden sowohl Schrägstrich (/) als auch umgekehrter Schrägstrich () als Verzeichnistrennzeichen verwendet. In anderen Umgebungen ist es der Schrägstrich (/) php.net/manual/en/function.basename.php
– OzzyCzech
28. Februar 2014 um 12:06 Uhr
Ich habe es jetzt behoben. Danke, @OzzyCzech.
– Theodore R. Smith
30. Dezember 2014 um 5:48 Uhr
@OzzyCzech Ich bin gerade darauf gestoßen, als ich von Windows zu Ubuntu gewechselt bin … zum Verrücktwerden. Aufgewickelt mit der in MaBis Update erwähnten Lösung.
– Chris Baker
14. Dezember 2015 um 16:20 Uhr
@OzzyCzech Wie kommt es, dass es nur unter Windows funktioniert? Die Frage bezog sich auf den vollqualifizierten Namespace-Namen, wenn ich mich auch vor Jahren nicht irre, und Namespaces sind nicht betriebssystemspezifisch und immer mit einem umgekehrten Schrägstrich wie Windows-Verzeichnistrennzeichen.
– FantomX1
13. Mai 2020 um 15:09 Uhr
Xorifelse
Ich befand mich in einer einzigartigen Situation, wo instanceof konnten nicht verwendet werden (insbesondere Namensraummerkmale) und I erforderlich den Kurznamen so effizient wie möglich zu verwenden, also habe ich selbst einen kleinen Benchmark durchgeführt. Es enthält alle verschiedenen Methoden und Variationen der Antworten auf diese Frage.
$bench = new \xori\Benchmark(1000, 1000); # https://github.com/Xorifelse/php-benchmark-closure
$shell = new \my\fancy\namespace\classname(); # Just an empty class named `classname` defined in the `\my\fancy\namespace\` namespace
$bench->register('strrpos', (function(){
return substr(static::class, strrpos(static::class, '\\') + 1);
})->bindTo($shell));
$bench->register('safe strrpos', (function(){
return substr(static::class, ($p = strrpos(static::class, '\\')) !== false ? $p + 1 : 0);
})->bindTo($shell));
$bench->register('strrchr', (function(){
return substr(strrchr(static::class, '\\'), 1);
})->bindTo($shell));
$bench->register('reflection', (function(){
return (new \ReflectionClass($this))->getShortName();
})->bindTo($shell));
$bench->register('reflection 2', (function($obj){
return $obj->getShortName();
})->bindTo($shell), new \ReflectionClass($shell));
$bench->register('basename', (function(){
return basename(str_replace('\\', "https://stackoverflow.com/", static::class));
})->bindTo($shell));
$bench->register('explode', (function(){
$e = explode("\\", static::class);
return end($e);
})->bindTo($shell));
$bench->register('slice', (function(){
return join('',array_slice(explode('\\', static::class), -1));
})->bindTo($shell));
print_r($bench->start());
Eine Liste der des gesamten Ergebnisses ist hier aber hier die Highlights:
Wenn Sie werden sowieso Reflektion verwenden, using $obj->getShortName() ist die schnellste Methode jedoch; Reflexion verwenden nur Um den Kurznamen zu erhalten, ist dies fast die langsamste Methode.
'strrpos' kann einen falschen Wert zurückgeben, wenn sich das Objekt nicht in einem Namensraum befindet, so while 'safe strrpos' ist ein kleines bisschen langsamer Ich würde sagen, das ist der Gewinner.
Zu machen 'basename' kompatibel zwischen Linux und Windows, die Sie verwenden müssen str_replace() was diese Methode zur langsamsten von allen macht.
Eine vereinfachte Ergebnistabelle, die Geschwindigkeit wird im Vergleich zur langsamsten Methode gemessen:
Es erscheint nahezu sinnlos, da in verschiedenen Namespaces dieselben Klassennamen definiert sein könnten. Wie werden Sie also damit umgehen? Und das liegt daran, dass der vollqualifizierte Klassenname in Ihrem Beispiel zurückgegeben wird
– Alma tun
11. November 2013 um 8:30 Uhr
Ich bin auf einem mobilen Gerät, daher kann ich keine anständige Antwort senden, aber die Lösung ist Reflektion, insbesondere ReflectionClass::getShortName – php.net/manual/en/reflectionclass.getshortname.php
– einsamer Tag
11. November 2013 um 8:55 Uhr
Für Leute, die nach einem Grund suchen, dies zu wollen: Es könnte in einer Hilfsfunktion in einer gemeinsamen Basisklasse nützlich sein (dh mehrere Namespaces sind in dieser Situation nie ein Problem).
– Darren Cook
16. Dezember 2013 um 9:05 Uhr