如何检查名称空间中是否存在类?


70

我有这个:

    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;

好吧……这种行为是非常不合理的(根据PHP创建不存在的类的对象)。有什么方法可以检查给定名称空间下是否存在类?


php.net/class_exists查看注释如何命名空间的说明
Royal Bg

Answers:


112

为了检查类,您必须使用名称空间(完整路径)指定它:

namespace Foo;
class Bar
{
}

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

-ie,您必须指定类的完整路径。您在名称空间而不是全局上下文中定义它。

但是,如果确实像在示例中一样在名称空间中导入类,则可以通过导入的名称而不是名称空间来引用该类,但这不允许您在动态构造中尤其是在那些表单类名称。例如,以下所有都会失败:

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

等等。问题在于处理导入的别名的机制。因此,在使用此类构造时,您必须指定完整路径:

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

$ref = 'Foo\Bar';
$obj = new $ref(); //ok

2
请注意,这Driver是在问题中导入的,因此此答案中的最后一个示例未描述所讨论的情况。use \Foo\Bar; $obj = new Bar;是完全合法的。真正的问题是class_exists() 没有考虑别名。
outis 2015年

@outis,谢谢。阅读此答案后,我陷入了无限循环,直到得到您的评论。
sanchez 2015年

1
@ san.chez虽然说的是真的,但真正的问题不关乎class_exists,而是关于PHP和别名实体的替代机制。添加了有关一般情况的说明。
Alma Do

2
class_exists('\\ Foo \\ Bar')不需要双斜杠,因为它对字符串使用单引号语法。php.net/manual/en/language.namespaces.dynamic.php
DrLightman

1
@AlmaDo,老实说,我不确定您从哪里获得您的信息。但最终,您可以做任何适合自己的解决方案。PHP 5.5于2013-06-20发行(请查阅php.net/releases/index.php#5.5.0 ip ),此问题于2014-03-14提出。在这个问题本身之前如何解决这个问题,更不用说PHP 5.5的发布日期了?使用::class永远不会带来多重结果。那怎么可能?关键是...您的答案对我的用例不起作用。我必须使用现在在生产中使用的@outis解决方案。
asiby

31

问题(如class_exists()手册页用户注释中所述)是,每当以字符串形式给出类名时,都不会考虑别名。这也会影响采用类名的其他函数,例如is_a()。因此,如果您在字符串中提供类名称,则必须包括完整的名称空间(例如'\XXX\Driver\Driver''XXX\\Driver\\Driver')。

PHP 5.5class为此引入了常量:

use XXX\Driver\Driver;
...
if (class_exists(Driver::class)) {
    ...
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.