173

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

4

6 回答 6

290
interface IInterface
{
}

class TheClass implements IInterface
{
}

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

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

于 2008-11-08T04:27:41.273 回答
119

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

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

于 2012-08-20T01:38:40.043 回答
57

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

于 2008-11-08T07:00:31.030 回答
25

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

if (is_subclass_of($my_class_instance, 'ISomeInterfaceName')){
    echo 'I can do it!';
}
于 2014-02-17T10:46:04.350 回答
15

更新

此处缺少该is_a 功能作为替代功能。

我做了一些性能测试来检查哪种方式是最好的。

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

It will return bool. The third parameter "allow_string" allows it to check class names without instantiating the class.

于 2020-03-04T01:25:44.240 回答
5

您还可以执行以下操作

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

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

于 2015-08-31T09:22:01.070 回答