Cum să verificați dacă clasa există într-un spațiu de nume? (Programare, Php, Oop, Spații De Nume)

Taruo Gene a intrebat.

Am înțeles acest lucru:

    use XXXDriverDriver;

...

var_dump(class_exists('Driver')); // false
        $driver = new Driver(); // prints 123123123 since I put an echo in the constructor of this class
        exit;

Ei bine… acest comportament este destul de irațional (crearea de obiecte de clase care, conform PHP, nu există). Există vreo modalitate de a verifica dacă o clasă există în cadrul unui anumit namespace?

Comentarii

  • php.net/class_exists consultați comentariile privind modul în care sunt date spațiile de nume –  > Por Royal Bg.
  • Vedeți și „Există o alternativă la class_exists() din PHP care să țină cont de namespace?”. –  > Por outis.
2 răspunsuri
Alma Do

Pentru a verifica clasa trebuie să o specificați cu namespace, calea completă:

namespace Foo;
class Bar
{
}

și

var_dump(class_exists('Bar'), class_exists('FooBar')); //false, true

-i.e. trebuie să specificați calea completă către clasă. Ați definit-o în namespace-ul dumneavoastră și nu în context global.

Cu toate acestea, dacă importați clasa în cadrul spațiului de nume, așa cum faceți în exemplul dvs., puteți face referire la ea prin intermediul numelui importat și fără spațiul de nume, dar acest lucru nu vă permite să faceți acest lucru în cadrul construcțiilor dinamice și, în special, în cadrul șirurilor de caractere în linie care formează numele clasei. De exemplu, toate următoarele vor eșua:

namespace Foo;
class Bar {
    public static function baz() {} 
}

use FooBar;

var_dump(class_exists('Bar')); //false
var_dump(method_exists('Bar', 'baz')); //false

$ref = "Bar";
$obj = new $ref(); //fatal

și așa mai departe. Problema se află în mecanica de lucru pentru aliasurile importate. Astfel, atunci când lucrați cu astfel de construcții, trebuie să specificați calea completă:

var_dump(class_exists('FooBar')); //true
var_dump(method_exists('FooBar', 'baz')); //true

$ref = 'FooBar';
$obj = new $ref(); //ok

Comentarii

  • Rețineți că Driver este importat în întrebare, deci ultimul exemplu din acest răspuns nu descrie cazul în cauză. use FooBar; $obj = new Bar; este perfect legal. Adevărata problemă este că class_exists() nu ia în considerare aliasurile. –  > Por outis.
  • @outis, Mulțumesc.Am fost într-o buclă infinită pentru o vreme după ce am citit acest răspuns până când am ajuns la comentariul tău. –  > Por sanchez.
  • @san.chez în timp ce ceea ce se spune este adevărat, adevărata problemă nu este despre class_exists, , ci despre PHP și mecanica de substituție pentru entitățile cu alias. Am adăugat explicația care se referă la cazul generic. –  > Por Alma Do.
  • class_exists(‘\Foo\Bar’) nu are nevoie de bariere duble, deoarece folosește sintaxa ghilimelelor simple pentru șirul de caractere. php.net/manual/ro/language.namespaces.dynamic.php –  > Por DrLightman.
  • @AlmaDo, sincer, nu sunt sigur de unde aveți informațiile. Dar, la sfârșitul zilei, puteți face orice soluție care funcționează pentru dvs. PHP 5.5 a fost lansat pe 2013-06-20 (căutați ip la php.net/releases/index.php#5.5.0) și această întrebare a fost pusă pe 2014-03-14. Cum poate orice răspuns la această întrebare să fie anterior întrebării în sine și cu atât mai puțin datei de lansare a PHP 5.5? Folosind ::class nu va aduce niciodată rezultate multiple. Cum este posibil așa ceva? Ideea este … răspunsul dvs. care nu a funcționat pentru cazurile mele de utilizare. A trebuit să folosesc soluția @outis pe care o folosesc acum în producție. –  > Por asiby.
outis

Problema (după cum se menționează în class_exists() pagina de manual note de utilizare) este că aliasurile nu sunt luate în considerare ori de câte ori un nume de clasă este dat sub formă de șir de caractere. Acest lucru afectează, de asemenea, alte funcții care iau un nume de clasă, cum ar fi is_a(). În consecință, dacă dați numele clasei într-un șir de caractere, trebuie să includeți spațiul de nume complet (de ex. 'XXXDriverDriver', , 'XXX\Driver\Driver').

PHP 5.5 a introdus funcția class pentru acest scop:

use XXXDriverDriver;
...
if (class_exists(Driver::class)) {
    ...
}