Jak uzyskać niekwalifikowaną (krótką) nazwę klasy obiektu?

153

Jak sprawdzić klasę obiektu w środowisku PHP z odstępami nazw bez określania pełnej klasy z przestrzenią nazw.

Załóżmy na przykład, że mam bibliotekę obiektów / Podmiot / Kontrakt / Nazwa.

Poniższy kod nie działa, ponieważ get_class zwraca pełną klasę z przestrzenią nazw.

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

Słowo kluczowe magic namespace zwraca aktualną przestrzeń nazw, która nie ma sensu, jeśli testowany obiekt ma inną przestrzeń nazw.

Mógłbym po prostu określić pełną nazwę klasy z przestrzeniami nazw, ale wydaje się, że blokuje to strukturę kodu. Nie przydałoby się też, gdybym chciał dynamicznie zmieniać przestrzeń nazw.

Czy ktoś może wymyślić skuteczny sposób, aby to zrobić. Myślę, że jedną z opcji jest regex.

Greg.Forbes
źródło
Wydaje się to prawie bezcelowe, ponieważ różne przestrzenie nazw mogą mieć zdefiniowane te same nazwy klas, więc jak sobie z tym poradzisz? A to dlatego, że w twojej próbce zwracana jest pełna kwalifikowana nazwa klasy
Alma Do
Jestem na urządzeniu mobilnym, więc nie mogę przesłać przyzwoitej odpowiedzi, ale rozwiązaniem jest refleksja, a konkretnie ReflectionClass :: getShortName - php.net/manual/en/reflectionclass.getshortname.php
lonesomeday
Dla osób szukających powodu, aby tego chcieć: może to być przydatne w funkcji pomocniczej we wspólnej klasie bazowej (tj. Wiele przestrzeni nazw nigdy nie stanowi problemu w tej sytuacji).
Darren Cook

Odpowiedzi:

182

Możesz to zrobić z refleksją. W szczególności można użyć ReflectionClass::getShortNamemetody, która pobiera nazwę klasy bez jej przestrzeni nazw.

Najpierw musisz zbudować ReflectionClassinstancję, a następnie wywołać getShortNamemetodę tej instancji:

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

Nie wyobrażam sobie jednak wielu okoliczności, w których byłoby to pożądane. Jeśli chcesz wymagać, aby obiekt był członkiem określonej klasy, możesz go przetestować za pomocą instanceof. Jeśli chcesz bardziej elastycznego sposobu sygnalizowania pewnych ograniczeń, sposobem na to jest napisanie interfejsu i wymaganie, aby kod implementował ten interfejs. Ponownie, poprawnym sposobem jest użycie instanceof. (Możesz to zrobić ReflectionClass, ale miałoby to znacznie gorszą wydajność.)

samotny dzień
źródło
1
@ Greg.Forbes Ponieważ Tenantnie istnieje w bieżącej przestrzeni nazw. Spróbuj var_dump($tenant instanceof \Library\Entity\People\Tenant)zamiast tego. Zbadaj także, jak używać useoperatora i ogólną koncepcję przestrzeni nazw PHP!
samotny dzień
3
Musiałem dodać ukośnik z przodu w ten sposób$reflect = new \ReflectionClass($object);
prograhammer
7
Generalnie nie lubię robić dużo voodoo ReflectionClass w mojej aplikacji, ponieważ może to prowadzić do nieoczekiwanych rezultatów, jeśli jest niewłaściwie używane (chronione metody stają się publiczne itp.). Można użyć prostego zastąpienia ciąg o PHP magicznych stałych zamiast: str_replace(__NAMESPACE__ . '\\', '', __CLASS__);. Jest również znacznie szybszy i wydajniejszy.
Franklin P Strube
2
@FranklinPStrube Chyba że brakuje mi czegoś, co pobiera krótką nazwę bieżącej klasy, a nie klasy obiektu. Zgadzam się, że używanie refleksji zwykle oznacza, że ​​robisz to źle.
samotny dzień
1
Wiele osób używa odbić do nadpisań widoczności elementów członkowskich, co jest ZŁE. Nie rób tego! Jednak stwierdzenie, że używanie Refleksji w ogóle to Voodoo i Doing It Wrong, daje ludziom złe wrażenie. Nie należy ich unikać, należy je zrozumieć i wiedzieć, kiedy są korzystne i na jakim poziomie abstrakcji.
Vanja D.
131

(new \ReflectionClass($obj))->getShortName(); to najlepsze rozwiązanie pod względem wydajności.

Byłem ciekawy, które z dostarczonych rozwiązań jest najszybsze, więc przygotowałem mały test.

Wyniki

Reflection: 1.967512512207 s ClassA
Basename:   2.6840535163879 s ClassA
Explode:    2.6507515668869 s ClassA

Kod

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";

Wyniki naprawdę mnie zaskoczyły. Myślałem, że rozwiązanie eksplozji będzie najszybszym sposobem ...

Hirnhamster
źródło
1
Świetna odpowiedź. Uruchomiłem ten sam kod, ale uzyskałem inny wynik (Macbook Pro i7, 16 GB RAM). Odbicie: 0,382, Basename: 0,380, Wybuch: 0,399. Myślę, że to zależy od twojego systemu, co jest najlepsze ...
Tobias Nyholm
4
Uruchom PHP 10000 razy z tym kodem, a uzyskasz lepszy wynik. Powyższe może pobrać odbicie z jakiejś puli, ale nie jest to zwykłe zachowanie tamtejszych aplikacji. Potrzebują tego tylko raz lub dwa razy.
LeMike
6
Zastanawiam się, czy ten test jest prawdziwy podczas tworzenia wystąpienia ReflectionClass na bardziej znaczącym obiekcie niż mały obiekt klasy A w twoim teście ...
Joe Green
2
uruchomienie tylko jednej iteracji zamiast 100000 daje znacznie inny wynik: Odbicie: 1,0967254638672 100000th / s ClassA Basename: 0,81062316894531 100000th / s ClassA Explode: 0,50067901611328 100000th / s ClassA
mcmurphy
1
eksplodować ('\\', static :: class) [0]? czy nie zwraca pierwszej części przestrzeni nazw? powinien zwrócić ostatnią część, a nie pierwszą
2oppin
86

Dodałem substr do testu https://stackoverflow.com/a/25472778/2386943 i to jest najszybszy sposób, w jaki mogłem przetestować (CentOS PHP 5.3.3, Ubuntu PHP 5.5.9) oba z i5.

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

Wyniki

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

Kod

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";

== AKTUALIZACJA ==

Jak wspomniano w komentarzach @MrBandersnatch, jest na to jeszcze szybszy sposób:

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

Oto zaktualizowane wyniki testu z „SubstringStrChr” (zapisuje do około 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
MaBi
źródło
5
Tylko dlatego, że podajemy pod kątem wydajności, okazało się, że jest to najszybsze, porównanie z testu dostarczonego w tym rozwiązaniu substr (strrchr (get_class ($ obj), '\\'), 1); Odbicie: 0,084223914146423 s Klasa A - Nazwa basenowa: 0,13206427097321 s Klasa A - Wybuch: 0,15331919193268 s Klasa A - Podłańcuch: 0,068068099021912 s Klasa A - Strrchar: 0,06472008228302 s Klasa A -
ctatro85
Właśnie natknąłem się na ten wątek i dodałem dodatkowy wzorzec do przetestowania str_replace(__NAMESPACE__ . '\\', '', __CLASS__);. Wyniki na słabej maszynie wirtualnej pokazały, że jest ona prawie dwa razy szybsza niż wszystkie inne. 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 masz rację. Przetestowałem Twoje rozwiązanie i zaoszczędziło mi to około 0,001 s. Zaktualizowałem moją odpowiedź Twoją!
MaBi
3
Ostrzeżenie: ten kod nie działa z klasami w globalnej przestrzeni nazw (tj. Ich pełna nazwa jest równa ich krótkiej nazwie)! I rada dla testu coś takiego: if ($pos = strrchr(static::class, '\\')) { .. } else { ... }.
Tristan Jahier
1
Aby to działało również w globalnej przestrzeni nazw, po prostu poprzedź nazwę klasy ukośnikiem odwrotnym :) - tj:$classNameShort = substr(strrchr('\\' . get_class($this), '\\'), 1);
rosell.dk
25

Oto prostszy sposób na zrobienie tego, jeśli używasz frameworka Laravel PHP:

<?php

// usage anywhere
// returns HelloWorld
$name = class_basename('Path\To\YourClass\HelloWorld');

// usage inside a class
// returns HelloWorld
$name = class_basename(__CLASS__);
spetsnaz
źródło
8
To nie jest wbudowana funkcja php, wygląda na funkcję pomocniczą udostępnianą przez laravel.
Steve Buzonas
6
Myślę, że to powiedział
Scott
4
Dzięki, używam Laravel i ta odpowiedź pozwoliła mi zaoszczędzić sporo czasu.
Jeremy Wadhams
18

Używam tego:

basename(str_replace('\\', '/', get_class($object)));
arzzzen
źródło
Możesz także spróbować: $ className = explode ('\\', basename (get_class ($ this))); $ className = array_pop ($ className); aby uzyskać zwykłą nazwę klasy. Lub użyj substr.
dompie
13
Działa tylko w systemie Windows W systemie Windows jako separator katalogów używany jest ukośnik (/) i ukośnik odwrotny (). W innych środowiskach jest to ukośnik (/) php.net/manual/en/function.basename.php
OzzyCzech
Naprawiłem to teraz. Dzięki, @OzzyCzech.
Theodore R. Smith
1
@OzzyCzech Właśnie natknąłem się na to podczas przechodzenia z systemu Windows na Ubuntu… irytowanie. Skończył się za pomocą rozwiązania wspomnianego w aktualizacji MaBi.
Chris Baker,
@OzzyCzech Dlaczego działa tylko w systemie Windows? pytanie dotyczyło w pełni kwalifikowanej nazwy przestrzeni nazw, jeśli się nie mylę również lata temu, a przestrzenie nazw nie są specyficzne dla systemu operacyjnego i zawsze są z odwrotnym ukośnikiem, takim jak separator katalogów w systemie Windows.
FantomX1
16

Aby otrzymać krótką nazwę jako jednowierszową (od PHP 5.4 ):

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

To czyste podejście i rozsądna szybkość .

flori
źródło
1
Zastanawiam się, jak to wypada w porównaniu z wyodrębnianiem ciągów w testach porównawczych. Wygląda na to, że będzie to znacznie wolniejsze.
Niezweryfikowany kontakt
12

Znalazłem się w wyjątkowej sytuacji, w której instanceofnie można było użyć (szczególnie cech z przestrzenią nazw) i potrzebowałem krótkiej nazwy w najbardziej efektywny sposób, więc zrobiłem mały test porównawczy. Zawiera wszystkie różne metody i warianty odpowiedzi na to pytanie.

$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());

Lista wszystkich wyników jest tutaj, ale oto najważniejsze informacje:

  • Jeśli mimo wszystko zamierzasz użyć odbicia, użycie $obj->getShortName()jest najszybszą metodą ; za pomocą refleksji tylko do uzyskania krótkiej nazwy jest to prawie najwolniejsza metoda.
  • 'strrpos' może zwrócić nieprawidłową wartość, jeśli obiekt nie znajduje się w przestrzeni nazw, więc while 'safe strrpos' jest trochę wolniejszy, powiedziałbym, że jest to zwycięzca.
  • Aby zapewnić 'basename'zgodność między systemami Linux i Windows, musisz użyćstr_replace() co sprawia, że ​​ta metoda jest najwolniejsza ze wszystkich.

Uproszczona tabela wyników, prędkość jest mierzona w porównaniu z najwolniejszą metodą:

+-----------------+--------+
| 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%  |
+-----------------+--------+
Xorifelse
źródło
8

Możesz użyć explodedo oddzielenia przestrzeni nazw i enduzyskania nazwy klasy:

$ex = explode("\\", get_class($object));
$className = end($ex);
m13r
źródło
7

Yii sposób

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

Yii używa tej metody w swoim generatorze kodu Gii

Dokumentacja metod

Ta metoda jest podobna do funkcji basename () w php, z tym wyjątkiem, że traktuje zarówno \, jak i / jako separatory katalogów, niezależnie od systemu operacyjnego. Ta metoda została stworzona głównie do pracy z przestrzeniami nazw php. Podczas pracy z prawdziwymi ścieżkami plików, basename () php powinno działać dobrze. Uwaga: ta metoda nie rozpoznaje rzeczywistego systemu plików ani składników ścieżki, takich jak „..”.

Więcej informacji:

https://github.com/yiisoft/yii2/blob/master/framework/helpers/BaseStringHelper.php http://www.yiiframework.com/doc-2.0/yii-helpers-basestringhelper.html#basename()-detail

mariovials
źródło
Witamy w Stack Overflow. Podaj więcej informacji, aby uzyskać odpowiedź. Co to robi i jak można go używać.
Jens
1
To działało dla mnie w systemie Windows, ale nie w Linuksie, być może dlatego, że przestrzenie nazw są w postaci odwrotnych ukośników Windows '\', podczas gdy linux basename uwzględnia separatory katalogów ukośniki "/". Więc popracowałem nad tym ze strtr. basename (strtr ($ class, '\\', '/'))
FantomX1,
6

Oto proste rozwiązanie dla 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()));
        }
    }
}

Co wróci?

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
}

Rozszerzona nazwa klasy i przestrzeń nazw sprawdzają się dobrze w przypadku:

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
}

A co z klasą w globalnej przestrzeni nazw?

namespace {

    class ClassWithoutNamespace {
        use \Names;
    }

    echo ClassWithoutNamespace::getNamespace() . PHP_EOL; // empty string
    echo ClassWithoutNamespace::getBaseClassName() . PHP_EOL; // ClassWithoutNamespace
}
OzzyCzech
źródło
3

Jeśli potrzebujesz znać nazwę klasy, która została wywołana z wnętrza klasy i nie chcesz jej przestrzeni nazw, możesz użyć tej

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

Jest to świetne, gdy masz metodę wewnątrz klasy, która jest rozszerzana przez inne klasy. Ponadto działa to również, jeśli przestrzenie nazw nie są w ogóle używane.

Przykład:

<?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)
Nino Škopac
źródło
2

Na podstawie odpowiedzi @MaBi zrobiłem to:

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

Którego możesz użyć w ten sposób:

namespace Foo\Bar\Baz;

class A
{
    use ClassShortNameTrait;
}

A::classwraca Foo\Bar\Baz\A, ale A::getClassShortName()wraca A.

Działa dla PHP> = 5.5.

Tristan Jahier
źródło
2

Wiem, że to stary post, ale tego właśnie używam - Szybciej niż wszystkie zamieszczone powyżej, po prostu wywołaj tę metodę z Twojej klasy, znacznie szybciej niż przy użyciu Reflection

namespace Foo\Bar\Baz;

class Test {
    public function getClass() {
        return str_replace(__NAMESPACE__.'\\', '', static::class);
    }
}
Seth
źródło
Niestety, działa to tylko wtedy, gdy wywołujesz to w klasie, której nazwę chcesz, a nie na dowolnej nazwie klasy jako ciągu.
jurchiks
1

Znalezione na stronie dokumentacji get_class , gdzie zostało umieszczone przeze mnie pod adresem nwhiting dot com .

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];
}

Ale idea przestrzeni nazw polega na uporządkowaniu kodu. Oznacza to również, że możesz mieć klasy o tej samej nazwie w wielu przestrzeniach nazw. Teoretycznie więc obiekt, który przekazujesz, mógłby mieć nazwę (pozbawioną) nazwę klasy, będąc jednocześnie obiektem zupełnie innym niż się spodziewasz.

Poza tym możesz chcieć sprawdzić określoną klasę bazową , w takim przypadku w get_classogóle nie działa. Możesz sprawdzić operatora instanceof.

GolezTrol
źródło
1

Możesz otrzymać nieoczekiwany wynik, gdy klasa nie ma przestrzeni nazw. To znaczy get_classwraca Foo, wtedy $baseClassbędzie oo.

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

Można to łatwo naprawić, poprzedzając get_classodwrotnym ukośnikiem:

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

Teraz również klasy bez przestrzeni nazw zwrócą właściwą wartość.

Tim
źródło
1

Stare, dobre wyrażenie regularne wydaje się być szybsze niż większość z poprzednich pokazanych metod:

// both of the below calls will output: ShortClassName

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

Działa to nawet wtedy, gdy podasz krótką nazwę klasy lub w pełni kwalifikowaną (kanoniczną) nazwę klasy.

To, co robi regex, polega na tym, że zużywa wszystkie poprzednie znaki, dopóki nie zostanie znaleziony ostatni separator (który również jest konsumowany). Zatem pozostały ciąg będzie krótką nazwą klasy.

Jeśli chcesz użyć innego separatora (np. /), Po prostu użyj tego separatora. Pamiętaj, aby usunąć znak ukośnika odwrotnego (tj. \), A także znak wzorca (tj. /) We wzorcu wejściowym.

Eugen Mihailescu
źródło
1

Ponieważ „ReflectionClass” może być zależne od wersji, użyj następującego:

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

lub nawet jasne

if(class_basename(ClassName::class) == 'ClassName') {
... do this ...
}
Martin Tonev
źródło
0

Cytując php.net:

W systemie Windows jako separator katalogów używany jest zarówno ukośnik (/), jak i ukośnik odwrotny (). W innych środowiskach jest to ukośnik (/).

Na podstawie tych informacji i rozwinięcia odpowiedzi arzzzen powinno to działać zarówno w systemach Windows, jak i Nix *:

<?php

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

Uwaga: wykonałem test porównawczy ReflectionClassprzeciwko, basename+str_replace+get_classa użycie odbicia jest około 20% szybsze niż przy użyciu podejścia basename, ale YMMV.

szumiąca
źródło
0

Najszybszym i najłatwiejszym rozwiązaniem, które sprawdza się w każdym środowisku, jest:

<?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"

?>
Fleshgrinder
źródło
1
Dlatego chciałbym, żeby PHP miało wewnętrzne operatory informacji o klasach. Utworzenie instancji zewnętrznego reflektora, aby zrobić coś, co powinno być tak proste, jak $Object->__class->getShortName()naprawdę wkurza mnie w PHP. Twoje podejście działa, ale teraz umieszczasz konkretne metody w swoich klasach, aby pokazać, co powinno być konstrukcją językową.
AgmLauncher
PHP bez funkcji „konkretnych” (lub powinniśmy je nazwać proceduralnymi) jest niemożliwe. Poczekajmy na PHP 6 (cóż, jeśli kiedykolwiek nadejdzie).
Fleshgrinder
0
$shortClassName = join('',array_slice(explode('\\', $longClassName), -1));
malhal
źródło
0

Jeśli usuwasz tylko spacje w nazwach i chcesz cokolwiek po ostatnim \ w nazwie klasy z przestrzenią nazw (lub tylko nazwie, jeśli nie ma '\'), możesz zrobić coś takiego:

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

Zasadniczo jest to wyrażenie regularne, aby uzyskać dowolną kombinację znaków lub odwrotnych ukośników w górę i do ostatniego odwrotnego ukośnika, a następnie zwrócić tylko znaki bez odwrotnego ukośnika w górę i do końca ciągu. Dodawanie? po pierwszej grupie oznacza, że ​​jeśli dopasowanie do wzorca nie istnieje, po prostu zwraca pełny ciąg.

Scott
źródło
0

Najszybszy że znalazłem tutaj PHP 7.2naUbubntu 18.04

preg_replace('/^(\w+\\\)*/', '', static::class)
Vasilii Suricov
źródło