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.
php
class
namespaces
Greg.Forbes
źródło
źródło
Odpowiedzi:
Możesz to zrobić z refleksją. W szczególności można użyć
ReflectionClass::getShortName
metody, która pobiera nazwę klasy bez jej przestrzeni nazw.Najpierw musisz zbudować
ReflectionClass
instancję, a następnie wywołaćgetShortName
metodę tej instancji: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życieinstanceof
. (Możesz to zrobićReflectionClass
, ale miałoby to znacznie gorszą wydajność.)źródło
Tenant
nie istnieje w bieżącej przestrzeni nazw. Spróbujvar_dump($tenant instanceof \Library\Entity\People\Tenant)
zamiast tego. Zbadaj także, jak używaćuse
operatora i ogólną koncepcję przestrzeni nazw PHP!$reflect = new \ReflectionClass($object);
str_replace(__NAMESPACE__ . '\\', '', __CLASS__);
. Jest również znacznie szybszy i wydajniejszy.(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
Kod
Wyniki naprawdę mnie zaskoczyły. Myślałem, że rozwiązanie eksplozji będzie najszybszym sposobem ...
źródło
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.
Wyniki
Kod
== AKTUALIZACJA ==
Jak wspomniano w komentarzach @MrBandersnatch, jest na to jeszcze szybszy sposób:
Oto zaktualizowane wyniki testu z „SubstringStrChr” (zapisuje do około 0,001 s):
źródło
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
if ($pos = strrchr(static::class, '\\')) { .. } else { ... }
.$classNameShort = substr(strrchr('\\' . get_class($this), '\\'), 1);
Oto prostszy sposób na zrobienie tego, jeśli używasz frameworka Laravel PHP:
źródło
Używam tego:
źródło
Aby otrzymać krótką nazwę jako jednowierszową (od PHP 5.4 ):
To czyste podejście i rozsądna szybkość .
źródło
Znalazłem się w wyjątkowej sytuacji, w której
instanceof
nie 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.Lista wszystkich wyników jest tutaj, ale oto najważniejsze informacje:
$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.'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ą:
źródło
Możesz użyć
explode
do oddzielenia przestrzeni nazw iend
uzyskania nazwy klasy:źródło
Yii sposób
Yii używa tej metody w swoim generatorze kodu Gii
Dokumentacja metod
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
źródło
Oto proste rozwiązanie dla PHP 5.4+
Co wróci?
Rozszerzona nazwa klasy i przestrzeń nazw sprawdzają się dobrze w przypadku:
A co z klasą w globalnej przestrzeni nazw?
źródło
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
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:
źródło
Na podstawie odpowiedzi @MaBi zrobiłem to:
Którego możesz użyć w ten sposób:
A::class
wracaFoo\Bar\Baz\A
, aleA::getClassShortName()
wracaA
.Działa dla PHP> = 5.5.
źródło
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
źródło
Znalezione na stronie dokumentacji get_class , gdzie zostało umieszczone przeze mnie pod adresem nwhiting dot com .
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_class
ogóle nie działa. Możesz sprawdzić operatorainstanceof
.źródło
Możesz otrzymać nieoczekiwany wynik, gdy klasa nie ma przestrzeni nazw. To znaczy
get_class
wracaFoo
, wtedy$baseClass
będzieoo
.Można to łatwo naprawić, poprzedzając
get_class
odwrotnym ukośnikiem:Teraz również klasy bez przestrzeni nazw zwrócą właściwą wartość.
źródło
Stare, dobre wyrażenie regularne wydaje się być szybsze niż większość z poprzednich pokazanych metod:
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.
źródło
Ponieważ „ReflectionClass” może być zależne od wersji, użyj następującego:
lub nawet jasne
źródło
Cytując php.net:
Na podstawie tych informacji i rozwinięcia odpowiedzi arzzzen powinno to działać zarówno w systemach Windows, jak i Nix *:
Uwaga: wykonałem test porównawczy
ReflectionClass
przeciwko,basename+str_replace+get_class
a użycie odbicia jest około 20% szybsze niż przy użyciu podejścia basename, ale YMMV.źródło
Najszybszym i najłatwiejszym rozwiązaniem, które sprawdza się w każdym środowisku, jest:
źródło
$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ą.źródło
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:
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.
źródło
Najszybszy że znalazłem tutaj
PHP 7.2
naUbubntu 18.04
źródło