检查实例的类是否实现了接口?

给定一个类实例,是否可以确定它是否实现了一个特定的接口?据我所知,没有一个内置函数可以直接完成这项工作。我有什么选择(如果有的话) ?

121106 次浏览
interface IInterface
{
}


class TheClass implements IInterface
{
}


$cls = new TheClass();
if ($cls instanceof IInterface) {
echo "yes";
}

您可以使用“ instanceof”运算符。要使用它,左操作数是一个类实例,右操作数是一个接口。如果对象实现了特定的接口,则返回 true。

Nlaq 指出,instanceof可以用来测试对象是否是实现接口的类的实例。

但是 instanceof不区分类类型和接口。你不知道这个对象是否是一个 同学们,它恰好被称为 IInterface

您还可以使用 PHP 中的反射 API 来更具体地测试这一点:

$class = new ReflectionClass('TheClass');
if ($class->implementsInterface('IInterface'))
{
print "Yep!\n";
}

参见 http://php.net/manual/en/book.reflection.php

正如 从这里开始指出的,您可以使用 class_implements()。与反射一样,这允许您将类名称指定为字符串,并且不需要类的实例:

interface IInterface
{
}


class TheClass implements IInterface
{
}


$interfaces = class_implements('TheClass');


if (isset($interfaces['IInterface'])) {
echo "Yes!";
}

class_implements()是 SPL 扩展的一部分。

见: http://php.net/manual/en/function.class-implements.php

性能测试

一些简单的性能测试显示了每种方法的成本:

给定一个对象的实例

Object construction outside the loop (100,000 iterations)
____________________________________________
| class_implements | Reflection | instanceOf |
|------------------|------------|------------|
| 140 ms           | 290 ms     | 35 ms      |
'--------------------------------------------'


Object construction inside the loop (100,000 iterations)
____________________________________________
| class_implements | Reflection | instanceOf |
|------------------|------------|------------|
| 182 ms           | 340 ms     | 83 ms      | Cheap Constructor
| 431 ms           | 607 ms     | 338 ms     | Expensive Constructor
'--------------------------------------------'

只给出一个类名

100,000 iterations
____________________________________________
| class_implements | Reflection | instanceOf |
|------------------|------------|------------|
| 149 ms           | 295 ms     | N/A        |
'--------------------------------------------'

其中代价高昂的 _ _ struct ()是:

public function __construct() {
$tmp = array(
'foo' => 'bar',
'this' => 'that'
);


$in = in_array('those', $tmp);
}

这些测试是基于 这个简单的代码的。

为了帮助将来的搜索,是 _ 子类 _ 的也是一个很好的变体(对于 PHP 5.3.7 +) :

if (is_subclass_of($my_class_instance, 'ISomeInterfaceName')){
echo 'I can do it!';
}

您还可以执行以下操作

public function yourMethod(YourInterface $objectSupposedToBeImplementing) {
//.....
}

如果 $objectSupposedToBeImplementing没有实现 YourInterface接口,它将抛出一个可恢复的错误。

更新

这里缺少 is_a 功能作为替代品。

我做了一些性能测试,以检查哪种方法的性能最好。

超过10万次迭代的结果

      instanceof [object] took   7.67 ms | +  0% | ..........
is_a [object] took  12.30 ms | + 60% | ................
is_a [class] took  17.43 ms | +127% | ......................
class_implements [object] took  28.37 ms | +270% | ....................................
reflection [class] took  34.17 ms | +346% | ............................................

添加了一些点来真正“感觉”看到差异。

由此生成: https://3v4l.org/8Cog7

结论

如果你有一个 对象来检查,使用 instanceof就像在接受的答案中提到的。

如果您需要检查 同学们,请使用 is_a

意外收获

假设您希望根据需要的接口实例化一个类,那么使用 is_a会更有优势。只有一个例外-当构造函数为空时。

例如: is_a(<className>, <interfaceName>, true);

第三个参数“ Allow _ string”允许它检查实例化类的类名 没有