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


148

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

Answers:


258
interface IInterface
{
}

class TheClass implements IInterface
{
}

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

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


102

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

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

性能测试

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

给定一个对象的实例

循环外的对象构造(100,000次迭代)
 ____________________________________________
| class_implements | 反思| instanceOf |
| ------------------ | ---------------- | ------------ |
| 140毫秒| 290毫秒| 35毫秒|
'--------------------------------------------'

循环内的对象构造(100,000次迭代)
 ____________________________________________
| class_implements | 反思| instanceOf |
| ------------------ | ---------------- | ------------ |
| 182毫秒| 340毫秒| 83毫秒| 廉价的构造函数
| 431毫秒| 607毫秒| 338毫秒| 昂贵的构造函数
'--------------------------------------------'

仅给出一个类名

100,000次迭代
 ____________________________________________
| class_implements | 反思| instanceOf |
| ------------------ | ---------------- | ------------ |
| 149毫秒| 295毫秒| N / A |
'--------------------------------------------'

昂贵的__construct()是:

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

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

这些测试基于此简单代码


56

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


2
这可以用于“静态”课程
Znarkus,2009年


@therefromhere:谢谢,很好的提示。这是SPL扩展的一部分。我的答案使用了反射扩展。
比尔·卡文

3
如果使用名称空间,则具有相同名称的接口和类之间不会存在歧义,并且可以安全地instanceof再次使用。
2012年

+1是class_implements()因为它显然可以更快地调用class_implements然后再调用in_array,而不是进行完整的反映
Nickolaus

19

只是为了帮助将来进行搜索,is_subclass_of还是一个不错的变体(对于PHP 5.3.7+):

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

5

您还可以执行以下操作

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

如果$objectSupposedToBeImplementing未实现YourInterfaceInterface ,则将引发可恢复的错误。


3

更新资料

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

结论

如果您有检查对象,请使用instance of已接受答案中所述的方法。

如果您要检查某个班级,请使用is_a

奖金

考虑到您想基于您需要的接口实例化一个类的情况,使用起来更加出色is_a。只有一个例外-构造函数为空时。

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

它将返回bool。第三个参数“ allow_string ”允许它在实例化类的情况下检查类名称。

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.