【问题标题】:Checking if an instance's class implements an interface?检查实例的类是否实现了接口?
【发布时间】:2010-09-21 10:07:24
【问题描述】:

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

【问题讨论】:

    标签: php interface oop


    【解决方案1】:
    interface IInterface
    {
    }
    
    class TheClass implements IInterface
    {
    }
    
    $cls = new TheClass();
    if ($cls instanceof IInterface) {
        echo "yes";
    }
    

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

    【讨论】:

    • 请注意,如果您试图确定类的构造函数,这将没有用
    【解决方案2】:

    正如therefromhere 指出的那样,您可以使用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

    性能测试

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

    给定一个对象的实例

    循环外的对象构造(100,000 次迭代) _______________________________________ |类实现 |反射 |实例 | |-------|------------|------------| | 140 毫秒 | 290 毫秒 | 35 毫秒 | '--------------------------------------------' 循环内的对象构造(100,000 次迭代) _______________________________________ |类实现 |反射 |实例 | |-------|------------|------------| | 182 毫秒 | 340 毫秒 | 83 毫秒 |便宜的构造函数 | 431 毫秒 | 607 毫秒 | 338 毫秒 |昂贵的构造函数 '--------------------------------------------'

    只给定一个类名

    100,000 次迭代 _______________________________________ |类实现 |反射 |实例 | |-----------------|------------|------------| | 149 毫秒 | 295 毫秒 |不适用 | '--------------------------------------------'

    昂贵的__construct()在哪里:

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

    这些测试基于this simple code

    【讨论】:

      【解决方案3】:

      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

      【讨论】:

      • 这可以用于“静态”类
      • @therefromhere:谢谢,很好的提示。这是 SPL 扩展的一部分。我的回答使用了反射扩展。
      • 如果你使用命名空间,那么同名的接口和类之间就不会有歧义,你可以再次安全地使用instanceof
      • +1 for class_implements() 因为调用 class_implements 然后 in_array 显然更快,而不是进行完整的反射
      【解决方案4】:

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

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

      【讨论】:

        【解决方案5】:

        更新

        这里缺少 is_a function 作为替代。

        我进行了一些性能测试,以检查哪种方式的性能最高。

        超过 100k 次迭代的结果

              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);

        它将返回bool。第三个参数“allow_string”允许它检查类名而不实例化类。

        【讨论】:

        【解决方案6】:

        您还可以执行以下操作

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

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

        【讨论】:

          猜你喜欢
          • 2018-10-19
          • 2016-09-29
          • 1970-01-01
          • 2018-07-26
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2016-10-13
          相关资源
          最近更新 更多