给定一个类实例,是否可以确定它是否实现了特定接口?据我所知,没有内置函数可以直接执行此操作。我有哪些选择(如果有)?
6 回答
interface IInterface
{
}
class TheClass implements IInterface
{
}
$cls = new TheClass();
if ($cls instanceof IInterface) {
echo "yes";
}
您可以使用“instanceof”运算符。要使用它,左操作数是类实例,右操作数是接口。如果对象实现了特定接口,则返回 true。
正如那里指出的那样,您可以使用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);
}
这些测试基于这个简单的代码。
nlaq 指出instanceof
可用于测试对象是否是实现接口的类的实例。
但instanceof
不区分类类型和接口。您不知道该对象是否是一个碰巧被调用的类IInterface
。
您还可以使用 PHP 中的反射 API 来更具体地进行测试:
$class = new ReflectionClass('TheClass');
if ($class->implementsInterface('IInterface'))
{
print "Yep!\n";
}
只是为了帮助将来的搜索is_subclass_of也是一个很好的变体(对于 PHP 5.3.7+):
if (is_subclass_of($my_class_instance, 'ISomeInterfaceName')){
echo 'I can do it!';
}
更新
此处缺少该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% | ............................................
添加了一些点以实际“感觉”看到差异。
结论
如果您有要检查的对象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.
您还可以执行以下操作
public function yourMethod(YourInterface $objectSupposedToBeImplementing) {
//.....
}
$objectSupposedToBeImplementing
如果没有实现YourInterface
接口,它将抛出一个可恢复的错误。