Wie erhalte ich den nicht qualifizierten (kurzen) Klassennamen eines Objekts?

Lesezeit: 12 Minuten

Benutzer-Avatar
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

Benutzer-Avatar
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

Benutzer-Avatar
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

Code

namespace foo\bar\baz;

class ClassA{
    public function getClassExplode(){
        return explode('\\', static::class)[0];
    }

    public function getClassReflection(){
        return (new \ReflectionClass($this))->getShortName();
    }

    public function getClassBasename(){
        return basename(str_replace('\\', "https://stackoverflow.com/", static::class));
    }
}

$a = new ClassA();
$num = 100000;

$rounds = 10;
$res = array(
    "Reflection" => array(),
    "Basename" => array(),
    "Explode" => array(),
);

for($r = 0; $r < $rounds; $r++){

    $start = microtime(true);
    for($i = 0; $i < $num; $i++){
        $a->getClassReflection();
    }
    $end = microtime(true);
    $res["Reflection"][] = ($end-$start);

    $start = microtime(true);
    for($i = 0; $i < $num; $i++){
        $a->getClassBasename();
    }
    $end = microtime(true);
    $res["Basename"][] = ($end-$start);

    $start = microtime(true);
    for($i = 0; $i < $num; $i++){
        $a->getClassExplode();
    }
    $end = microtime(true);
    $res["Explode"][] = ($end-$start);
}

echo "Reflection: ".array_sum($res["Reflection"])/count($res["Reflection"])." s ".$a->getClassReflection()."\n";
echo "Basename: ".array_sum($res["Basename"])/count($res["Basename"])." s ".$a->getClassBasename()."\n";
echo "Explode: ".array_sum($res["Explode"])/count($res["Explode"])." s ".$a->getClassExplode()."\n";

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

Benutzer-Avatar
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.

$classNameWithNamespace=get_class($this);
return substr($classNameWithNamespace, strrpos($classNameWithNamespace, '\\')+1);

Ergebnisse

Reflection: 0.068084406852722 s ClassA
Basename: 0.12301609516144 s ClassA
Explode: 0.14073524475098 s ClassA
Substring: 0.059865570068359 s ClassA 

Code

namespace foo\bar\baz;
class ClassA{
  public function getClassExplode(){
    $c = array_pop(explode('\\', get_class($this)));
    return $c;
  }

  public function getClassReflection(){
    $c = (new \ReflectionClass($this))->getShortName();
    return $c;
  }

  public function getClassBasename(){
    $c = basename(str_replace('\\', "https://stackoverflow.com/", get_class($this)));
    return $c;
  }

  public function getClassSubstring(){
    $classNameWithNamespace = get_class($this);
    return substr($classNameWithNamespace, strrpos($classNameWithNamespace, '\\')+1);
  }
}

$a = new ClassA();
$num = 100000;

$rounds = 10;
$res = array(
    "Reflection" => array(),
    "Basename" => array(),
    "Explode" => array(),
    "Substring" => array()
);

for($r = 0; $r < $rounds; $r++){

  $start = microtime(true);
  for($i = 0; $i < $num; $i++){
    $a->getClassReflection();
  }
  $end = microtime(true);
  $res["Reflection"][] = ($end-$start);

  $start = microtime(true);
  for($i = 0; $i < $num; $i++){
    $a->getClassBasename();
  }
  $end = microtime(true);
  $res["Basename"][] = ($end-$start);

  $start = microtime(true);
  for($i = 0; $i < $num; $i++){
    $a->getClassExplode();
  }
  $end = microtime(true);
  $res["Explode"][] = ($end-$start);

  $start = microtime(true);
  for($i = 0; $i < $num; $i++){
    $a->getClassSubstring();
  }
  $end = microtime(true);
  $res["Substring"][] = ($end-$start);
}

echo "Reflection: ".array_sum($res["Reflection"])/count($res["Reflection"])." s ".$a->getClassReflection()."\n";
echo "Basename: ".array_sum($res["Basename"])/count($res["Basename"])." s ".$a->getClassBasename()."\n";
echo "Explode: ".array_sum($res["Explode"])/count($res["Explode"])." s ".$a->getClassExplode()."\n";
echo "Substring: ".array_sum($res["Substring"])/count($res["Substring"])." s ".$a->getClassSubstring()."\n";

==AKTUALISIEREN==

Wie in den Kommentaren von @MrBandersnatch erwähnt, gibt es dafür sogar einen schnelleren Weg:

return substr(strrchr(get_class($this), '\\'), 1);

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


Benutzer-Avatar
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));
}

Benutzer-Avatar
arzzen

Ich benutze das:

basename(str_replace('\\', "https://stackoverflow.com/", get_class($object)));

  • 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

Benutzer-Avatar
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

Benutzer-Avatar
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:

+-----------------+--------+
| registered name | speed  |
+-----------------+--------+
| reflection 2    | 70.75% |
| strrpos         | 60.38% |
| safe strrpos    | 57.69% |
| strrchr         | 54.88% |
| explode         | 46.60% |
| slice           | 37.02% |
| reflection      | 16.75% |
| basename        | 0.00%  |
+-----------------+--------+

1361500cookie-checkWie erhalte ich den nicht qualifizierten (kurzen) Klassennamen eines Objekts?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy