Wie erhalte ich den unqualifizierten (kurzen) Klassennamen eines Objekts?


153

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.


Es scheint nahezu sinnlos zu sein, da in verschiedenen Namespaces dieselben Klassennamen definiert sein können. Wie werden Sie damit umgehen? Und das liegt daran, dass der vollständig qualifizierte Klassenname in Ihrer Stichprobe zurückgegeben wird
Alma Do

Ich bin auf einem mobilen Gerät, daher kann ich keine anständige Antwort einreichen, aber die Lösung ist Reflection, insbesondere ReflectionClass :: getShortName - php.net/manual/en/reflectionclass.getshortname.php
lonesomeday

Für Leute, die nach einem Grund suchen, dies zu wollen: Es kann in einer Hilfsfunktion in einer gemeinsamen Basisklasse nützlich sein (dh mehrere Namespaces sind in dieser Situation niemals ein Problem).
Darren Cook

Antworten:


182

Sie können dies mit Reflexion tun. Insbesondere können Sie die verwendenReflectionClass::getShortName Methode verwenden, die den Namen der Klasse ohne ihren Namespace abruft.

Zuerst müssen Sie eine ReflectionClassInstanz erstellen und dann die getShortNameMethode dieser Instanz aufrufen :

$reflect = new ReflectionClass($object);
if ($reflect->getShortName() === 'Name') {
    // do this
}

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 tun instanceof. (Sie können es damit machen ReflectionClass, aber es hätte eine viel schlechtere Leistung.)


1
@ Greg.Forbes Da Tenantim aktuellen Namespace nicht vorhanden. Versuchen Sie es var_dump($tenant instanceof \Library\Entity\People\Tenant)stattdessen. Untersuchen Sie auch die Verwendung des useOperators und das allgemeine Konzept hinter PHP-Namespaces!
einsamer

3
Ich musste einen Schrägstrich wie diesen $reflect = new \ReflectionClass($object);
hinzufügen

7
Im Allgemeinen mache ich 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 einen einfachen String-Ersatz für magische PHP-Konstanten verwenden : str_replace(__NAMESPACE__ . '\\', '', __CLASS__);. Es ist auch viel schneller, was die Leistung betrifft.
Franklin P Strube

2
@FranklinPStrube Wenn mir nichts fehlt, wird der Kurzname der aktuellen Klasse und nicht die Klasse des Objekts angezeigt. Ich bin damit einverstanden, dass die Verwendung von Reflexion normalerweise bedeutet, dass Sie es falsch machen.
einsamer

1
Viele Leute verwenden Reflections zum Überschreiben der Sichtbarkeit von Mitgliedern, was SCHLECHT ist. TU das nicht! Die Aussage, dass die Verwendung von Reflections im Allgemeinen Voodoo ist und Doing It Wrong den Menschen den falschen Eindruck vermittelt. Sie sollten sie nicht vermeiden, Sie sollten sie verstehen und wissen, wann sie nützlich sind und auf welcher Abstraktionsebene.
Vanja D.

131

(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

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('\\', '/', 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 ...


1
Gute Antwort. Ich habe den gleichen 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

4
Führen Sie PHP 10 000 Mal mit diesem Code aus und Sie erhalten ein besseres Ergebnis. Das Obige könnte 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

6
Ich frage mich, ob dieser Test zutrifft, wenn eine ReflectionClass auf einem wesentlicheren Objekt als dem kleinen Objekt der Klasse A in Ihrem Test instanziiert wird ...
Joe Green

2
Das Ausführen von nur einer Iteration anstelle von 100000 führt zu einem ganz anderen Ergebnis: Reflexion: 1.0967254638672 100000. / s ClassA Basisname: 0.81062316894531 100000th / s ClassA Explode: 0.50067901611328 100000th / s ClassA
mcmurphy

1
explodieren ('\\', static :: class) [0]? Gibt es nicht den ersten Teil des Namespace zurück? sollte letzten Teil zurückgeben, nicht zuerst
2oppin

86

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.

$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('\\', '/', 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";

== UPDATE ==

Wie in den Kommentaren von @MrBandersnatch erwähnt, gibt es noch einen schnelleren Weg, dies zu tun:

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

Hier sind die aktualisierten Testergebnisse mit "SubstringStrChr" (spart bis zu 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

5
Nur weil wir die Effizienz auflisten, fand ich, dass dies der schnellste Vergleich mit dem in diesem Lösungssubstrat bereitgestellten Test ist (strrchr (get_class ($ obj), '\\'), 1); Reflexion: 0,084223914146423 s Klasse A - Basisname: 0,13206427097321 s Klasse A - Explosion: 0,15331919193268 s Klasse A - Teilzeichenfolge: 0,068068099021912 s Klasse A - Strrchar: 0,06472008228302 s Klasse A -
ctatro85

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 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
Franklin P Strube

1
@ MrBandersnatch Sie sind richtig. Ich habe Ihre Lösung getestet und dadurch ca. 0,001 s eingespart. Ich habe meine Antwort mit Ihrer aktualisiert!
MaBi

3
Warnung: Dieser Code funktioniert nicht mit Klassen im globalen Namespace (dh ihr vollständiger Name entspricht ihrem Kurznamen)! Ich rate, etwas zu testen wie : if ($pos = strrchr(static::class, '\\')) { .. } else { ... }.
Tristan Jahier

1
Damit es auch im globalen Namespace funktioniert, stellen Sie dem Klassennamen einfach einen Backslash voran :) - dh:$classNameShort = substr(strrchr('\\' . get_class($this), '\\'), 1);
rosell.dk

25

Dies ist eine einfachere Möglichkeit, 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__);

8
Dies ist keine eingebaute PHP-Funktion, sondern sieht aus wie eine Hilfsfunktion von Laravel.
Steve Buzonas

6
Ich denke, er sagte das
Scott

4
Danke, ich benutze Laravel und diese Antwort hat mir viel Zeit gespart.
Jeremy Wadhams


18

Ich benutze das:

basename(str_replace('\\', '/', 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

13
Funktioniert nur unter Windows Unter Windows werden sowohl Schrägstrich (/) als auch Backslash () als Verzeichnistrennzeichen verwendet. In anderen Umgebungen ist es der Schrägstrich (/) php.net/manual/en/function.basename.php
OzzyCzech

Ich habe es jetzt behoben. Danke, @OzzyCzech.
Theodore R. Smith

1
@OzzyCzech Ich bin gerade darauf gestoßen, als ich von Windows zu Ubuntu gewechselt bin ... verrückt. Wurde mit der im MaBi-Update genannten Lösung abgewickelt.
Chris Baker

@OzzyCzech Wie kommt es, dass es nur unter Windows funktioniert? Die Frage betraf den vollständig qualifizierten Namespace-Namen, wenn ich mich auch vor Jahren nicht geirrt habe und Namespaces nicht betriebssystemspezifisch sind und immer einen Backslash wie das Windows-Verzeichnis-Trennzeichen aufweisen.
FantomX1

16

So erhalten Sie den Kurznamen als Einzeiler (seit PHP 5.4 ):

echo (new ReflectionClass($obj))->getShortName();

Es ist ein sauberer Ansatz und vernünftig schnell .


1
Ich frage mich, wie sich dies mit einer String-Extraktion in Benchmarks vergleichen lässt. Es scheint, dass dies viel langsamer wäre.
Unverifizierter Kontakt

12

Ich befand mich in einer einzigartigen Situation, in der ich instanceofnicht 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.

$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('\\', '/', 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 des gesamten Ergebnisses finden Sie hier, aber hier sind die Highlights:

  • Wenn Sie sowieso Verwendung Reflexion gehen, verwenden $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.
  • Um die 'basename'Kompatibilität zwischen Linux und Windows zu gewährleisten, müssen Sie diese verwenden str_replace(), wodurch diese Methode die langsamste von allen ist.

In einer vereinfachten Ergebnistabelle wird die Geschwindigkeit 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%  |
+-----------------+--------+

8

Sie können explodeden Namespace trennen und endden Klassennamen abrufen:

$ex = explode("\\", get_class($object));
$className = end($ex);

7

Yii Weg

\yii\helpers\StringHelper::basename(get_class($model));

Yii verwendet diese Methode in seinem Gii-Codegenerator

Methodendokumentation

Diese Methode ähnelt der PHP-Funktion basename (), behandelt jedoch sowohl \ als auch / als Verzeichnistrennzeichen, unabhängig vom Betriebssystem. Diese Methode wurde hauptsächlich für PHP-Namespaces entwickelt. Wenn Sie mit echten Dateipfaden arbeiten, sollte der Basisname () von PHP für Sie gut funktionieren. Hinweis: Diese Methode kennt weder das tatsächliche Dateisystem noch Pfadkomponenten wie "..".

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


Willkommen bei Stack Overflow. Bitte geben Sie weitere Informationen für Ihre Antwort an. Was macht das und wie kann man es benutzen.
Jens

1
Dies funktionierte für mich unter Windows, aber nicht unter Linux, möglicherweise weil Namespaces in Form von Windows-Verzeichnissen Backslashes '\' vorliegen, während Linux-Basisname Verzeichnis-Trennzeichen als Schrägstriche '/' berücksichtigt. Also habe ich es mit strtr herumgearbeitet. ' Basisname (strtr ($ class, '\\', '/'))
FantomX1

6

Hier ist eine einfache Lösung für PHP 5.4+

namespace {
    trait Names {
        public static function getNamespace() {
            return implode('\\', array_slice(explode('\\', get_called_class()), 0, -1));
        }

        public static function getBaseClassName() {
            return basename(str_replace('\\', '/', get_called_class()));
        }
    }
}

Was wird zurückgegeben?

namespace x\y\z {
    class SomeClass {
        use \Names;
    }

    echo \x\y\z\SomeClass::getNamespace() . PHP_EOL; // x\y\z
    echo \x\y\z\SomeClass::getBaseClassName() . PHP_EOL; // SomeClass
}

Der erweiterte Klassenname und der erweiterte Namespace eignen sich gut für:

namespace d\e\f {

    class DifferentClass extends \x\y\z\SomeClass {

    }

    echo \d\e\f\DifferentClass::getNamespace() . PHP_EOL; // d\e\f
    echo \d\e\f\DifferentClass::getBaseClassName() . PHP_EOL; // DifferentClass
}

Was ist mit der Klasse im globalen Namespace?

namespace {

    class ClassWithoutNamespace {
        use \Names;
    }

    echo ClassWithoutNamespace::getNamespace() . PHP_EOL; // empty string
    echo ClassWithoutNamespace::getBaseClassName() . PHP_EOL; // ClassWithoutNamespace
}

3

Wenn Sie den Klassennamen kennen müssen, der innerhalb einer Klasse aufgerufen wurde, und den Namespace nicht möchten, können Sie diesen verwenden

$calledClass = get_called_class();
$name = strpos($calledClass, '\\') === false ?
    $calledClass : substr($calledClass, strrpos($calledClass, '\\') + 1);

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:

<?php
namespace One\Two {
    class foo
    {
        public function foo()
        {
            $calledClass = get_called_class();
            $name = strpos($calledClass, '\\') === false ?
                $calledClass : substr($calledClass, strrpos($calledClass, '\\') + 1);

            var_dump($name);
        }
    }
}

namespace Three {
    class bar extends \One\Two\foo
    {
        public function bar()
        {
            $this->foo();
        }
    }
}

namespace {
    (new One\Two\foo)->foo();
    (new Three\bar)->bar();
}

// test.php:11:string 'foo' (length=3)
// test.php:11:string 'bar' (length=3)

2

Basierend auf der Antwort von @MaBi habe ich Folgendes gemacht:

trait ClassShortNameTrait
{
    public static function getClassShortName()
    {
        if ($pos = strrchr(static::class, '\\')) {
            return substr($pos, 1);
        } else {
            return static::class;
        }
    }
}

Was Sie so verwenden können:

namespace Foo\Bar\Baz;

class A
{
    use ClassShortNameTrait;
}

A::classkehrt zurück Foo\Bar\Baz\A, A::getClassShortName()kehrt aber zurück A.

Funktioniert für PHP> = 5.5.


2

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

namespace Foo\Bar\Baz;

class Test {
    public function getClass() {
        return str_replace(__NAMESPACE__.'\\', '', static::class);
    }
}

Leider funktioniert das nur, wenn Sie es in der Klasse aufrufen, deren Namen Sie möchten, und nicht in einem beliebigen Klassennamen als Zeichenfolge.
Jurchiks

1

Gefunden auf der Dokumentationsseite von get_class , wo es von mir bei nwhiting dot com gepostet wurde .

function get_class_name($object = null)
{
    if (!is_object($object) && !is_string($object)) {
        return false;
    }

    $class = explode('\\', (is_string($object) ? $object : get_class($object)));
    return $class[count($class) - 1];
}

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_classreicht der Trick überhaupt nicht aus. Vielleicht möchten Sie den Operator überprüfen instanceof.


1

Möglicherweise erhalten Sie ein unerwartetes Ergebnis, wenn die Klasse keinen Namespace hat. Dh get_classkehrt Foo, dann $baseClasswäre oo.

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

Dies kann leicht behoben werden, indem get_classein Backslash vorangestellt wird :

$baseClass = substr(strrchr('\\'.get_class($this), '\\'), 1);

Jetzt geben auch Klassen ohne Namespace den richtigen Wert zurück.


1

Ein guter alter Regex scheint schneller zu sein als die meisten der zuvor gezeigten Methoden:

// both of the below calls will output: ShortClassName

echo preg_replace('/.*\\\\/', '', 'ShortClassName');
echo preg_replace('/.*\\\\/', '', 'SomeNamespace\SomePath\ShortClassName');

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.


1

Da "ReflectionClass" versionabhängig sein kann, verwenden Sie einfach Folgendes:

if(class_basename(get_class($object)) == 'Name') {
... do this ...
}

oder sogar klar

if(class_basename(ClassName::class) == 'ClassName') {
... do this ...
}

0

Zitieren von php.net:

Unter Windows werden sowohl Schrägstrich (/) als auch Backslash () als Verzeichnistrennzeichen verwendet. In anderen Umgebungen ist dies der Schrägstrich (/).

Basierend auf diesen Informationen und der Erweiterung von arzzzen answer sollte dies sowohl auf Windows- als auch auf Nix * -Systemen funktionieren:

<?php

if (basename(str_replace('\\', '/', get_class($object))) == 'Name') {
    // ... do this ...
}

Hinweis: Ich habe einen Benchmark von ReflectionClassgegen basename+str_replace+get_classund Reflexion durchgeführt, der ungefähr 20% schneller ist als der Basisnamen-Ansatz, aber YMMV.


0

Die schnellste und einfachste Lösung, die in jeder Umgebung funktioniert, ist:

<?php

namespace \My\Awesome\Namespace;

class Foo {

  private $shortName;

  public function fastShortName() {
    if ($this->shortName === null) {
      $this->shortName = explode("\\", static::class);
      $this->shortName = end($this->shortName);
    }
    return $this->shortName;
  }

  public function shortName() {
    return basename(strtr(static::class, "\\", "/"));
  }

}

echo (new Foo())->shortName(); // "Foo"

?>

1
Aus diesem Grund wünschte ich mir, PHP hätte interne Klasseninformationsoperatoren. Das Instanziieren eines externen Reflektors, um das zu tun, was so einfach wie möglich sein sollte, macht $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.
AgmLauncher

PHP ohne "konkrete" (oder sollten wir sie prozedurale) Funktionen ist unmöglich. Warten wir auf PHP 6 (falls es jemals kommt).
Fleischwolf

0
$shortClassName = join('',array_slice(explode('\\', $longClassName), -1));

0

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:

$base_class = preg_replace('/^([\w\\\\]+\\\\)?([^\\\\]+)$/', '$2', get_class($myobject));

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.


0

Am schnellsten habe ich hier für PHP 7.2am gefundenUbubntu 18.04

preg_replace('/^(\w+\\\)*/', '', static::class)
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.