Wie überprüfe ich, ob eine Klasse in einem Namespace vorhanden ist?

70

Ich habe das:

    use XXX\Driver\Driver;

...

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

Nun ... dieses Verhalten ist ziemlich irrational (Objekte von Klassen erstellen, die laut PHP nicht existieren). Gibt es eine Möglichkeit zu überprüfen, ob eine Klasse unter einem bestimmten Namespace vorhanden ist?

Taruo Gene
quelle
php.net/class_exists Schauen Sie sich die Kommentare an, wie Namespaces vergeben werden
Royal Bg

Antworten:

112

Um die Klasse zu überprüfen, müssen Sie sie mit dem Namespace und dem vollständigen Pfad angeben:

namespace Foo;
class Bar
{
}

und

var_dump(class_exists('Bar'), class_exists('\Foo\Bar')); //false, true

-ie Sie müssen den vollständigen Pfad zur Klasse angeben. Sie haben es in Ihrem Namespace und nicht im globalen Kontext definiert.

Wenn Sie die Klasse jedoch wie in Ihrem Beispiel in den Namespace importieren, können Sie sie über einen importierten Namen und ohne Namespace referenzieren. Dies ermöglicht Ihnen jedoch nicht, dies in dynamischen Konstruktionen und insbesondere in Inline-Zeichenfolgen zu tun bildet Klassennamen. Zum Beispiel schlagen alle folgenden fehl:

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

use Foo\Bar;

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

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

und so weiter. Das Problem liegt in der Mechanik der Arbeit für importierte Aliase. Wenn Sie mit solchen Konstruktionen arbeiten, müssen Sie den vollständigen Pfad angeben:

var_dump(class_exists('\Foo\Bar')); //true
var_dump(method_exists('\Foo\Bar', 'baz')); //true

$ref = 'Foo\Bar';
$obj = new $ref(); //ok
Alma Do.
quelle
2
Beachten Sie, dass dies Driverin die Frage importiert wird, sodass das letzte Beispiel in dieser Antwort den fraglichen Fall nicht beschreibt. use \Foo\Bar; $obj = new Bar;ist vollkommen legal. Das eigentliche Problem ist, dass class_exists() Aliase nicht berücksichtigt werden.
Outis
@outis, danke. Ich war eine Weile in einer Endlosschleife, nachdem ich diese Antwort gelesen hatte, bis ich zu Ihrem Kommentar kam.
Sanchez
1
@ san.chez Während das Gesagte wahr ist, geht es beim eigentlichen Problem nicht class_existsum PHP und Substitutionsmechanismen für Alias-Entitäten. Erklärung hinzugefügt, die sich auf den allgemeinen Fall bezieht.
Alma Do
2
class_exists ('\\ Foo \\ Bar') benötigt keine doppelten Schrägstriche, da für die Zeichenfolge die Syntax in einfachen Anführungszeichen verwendet wird. php.net/manual/en/language.namespaces.dynamic.php
DrLightman
1
@AlmaDo, ehrlich gesagt bin ich mir nicht sicher, woher du deine Informationen bekommst. Aber am Ende des Tages können Sie jede Lösung machen, die für Sie funktioniert. PHP 5.5 wurde am 20.06.2013 veröffentlicht (siehe IP unter php.net/releases/index.php#5.5.0 ) und diese Frage wurde am 14.03.2014 gestellt. Wie kann eine Antwort auf diese Frage der Frage selbst vorausgehen und geschweige denn das Veröffentlichungsdatum von PHP 5.5? Die Verwendung ::classführt niemals zu mehreren Ergebnissen. Wie ist das möglich? Der Punkt ist ... Ihre Antwort, die für meine Anwendungsfälle nicht funktioniert hat. Ich musste die @ outis-Lösung verwenden, die ich jetzt in der Produktion verwende.
Asiby
31

Das Problem (wie in den class_exists()Benutzerhinweisen auf der Handbuchseite erwähnt ) ist, dass Aliase nicht berücksichtigt werden, wenn ein Klassenname als Zeichenfolge angegeben wird. Dies wirkt sich auch auf andere Funktionen aus, die einen Klassennamen annehmen, z is_a(). Wenn Sie den Klassennamen in eine Zeichenfolge eingeben, müssen Sie daher den vollständigen Namespace einschließen (z '\XXX\Driver\Driver'.'XXX\\Driver\\Driver' ).

PHP 5.5 führte die classKonstante genau zu diesem Zweck ein:

use XXX\Driver\Driver;
...
if (class_exists(Driver::class)) {
    ...
}
outis
quelle