instanceof或method_exist应该使用哪一个?

时间:2015-02-27 14:23:46

标签: php function class-design instanceof

在我的验证类中,我传递了不同的类对象,需要在这些类上调用方法。现在的问题是。如何确保该方法存在。

我应该像这样使用instanceof

...
...
if($passedObject instanceof MyExpectedClass) {
   //then call the rquired method
}
...
...

或者应该像这样method_exists

...
...
if(method_exists($passedObject, 'MyExpectedMethod')) {
   //then call the rquired method
}
...
...

我很困惑。哪一个更好的方法。

修改

我知道如果传递的Object是期望类的一个实例,那么预期的方法也将存在,因为MyExpected类实现了包含预期方法的接口。希望这将使情景更加清晰。

4 个答案:

答案 0 :(得分:1)

这是两种不同的验证,instanceof检查提供的对象是否是特定类的实例,而method_exists检查某个类中是否存在某个方法,因此第一次验证将永远不会告诉您传递的对象是否包含该方法,它只会告诉你它是该方法的一个实例。你应该使用method_exists()

简单测试

class MyClass {
   public function myMethod() {
       // code
   }
}
$obj = new MyClass;
var_dump(method_exists($obj, 'myMethod')); // true

答案 1 :(得分:0)

您可以创建一个界面:

interface ExpectedMethodInterface
{
    /**
     * My expected method
     *
     * @return ...expected return type...
     */
    public function myExpectedMethod();
}

然后每个具有此方法的类应该实现如下接口:

class MyClassWithExpectedMethod implements ExpectedMethodInterface
{
    /**
     * My expected method
     *
     * @return ...expected return type...
     */
    public function myExpectedMethod()
    {
        ...body for method...
    }
}

然后你可以检查:

if($passedObject instanceof ExpectedMethodInterface) 
{
    ... call your method...
}

如果你使用php 5.4.0或更高版本,你也可以制作一个特性并在你的课程中使用它来防止代码重复:

trait ExpectedMethodTrait
{
    /**
     * My expected method
     *
     * @return ...expected return type...
     */
    public function myExpectedMethod()
    {
        ...body for method...
    }
}

然后使用你的特征:

class MyClassWithExpectedMethod implements ExpectedMethodInterface
{
    use ExpectedMethodTrait;
}

答案 2 :(得分:0)

如果您正在寻找最有效的方法,那么instanceOf会更好,但不会更多。

interface HasMethod {
    public function myMethod();
}

class MyClass1 implements HasMethod {
    public function myMethod() {}
}

class MyClass2 {
    public function myMethod() {}
}

$myClass1 = new MyClass1();
$myClass2 = new MyClass2();

$times = [0,0,0];
$j = 0;
for($i = 0; $i < 100000; ++$i) {
    $start = microtime(1);
    ($myClass1 instanceof HasMethod) && $j++;
    $times[0] += microtime(1) - $start;

    $start = microtime(1);
    (method_exists($myClass1, 'myMethod')) && $j++;
    $times[1] += microtime(1) - $start;

    $start = microtime(1);
    (method_exists($myClass2, 'myMethod')) && $j++;
    $times[2] += microtime(1) - $start;
}

print_r($times);

结果:

Array
(
    [0] => 0.46121835708618 //instanceOf with interface
    [1] => 0.53055930137634 //method_exists with interface
    [2] => 0.4961085319519  //method_exists without interface
)

请记住method_exists可以将结果缓存到所调用的特定类 - Reflection类只检查一次给定的类,无论你创建了多少个Reflection实例 - 这是一个性能问题,因为类实例不会在运行时更改定义,因此反射重复工作中没有任何意义可以产生相同的结果。我不知道这是否适用于这种情况,但它应该适用相同的规则。

如果您反复在许多不同的对象上调用instanceofmethod_exists,上述示例显然不适用 - 但我建议您专注于代码简单性,可读性和重复数据删除,因为此处显示的示例显示每个选项的处理时间差异可以忽略不计。

不存在

就像事后的想法一样,我再次运行相同的检查,这次寻找一个不存在的方法,一个未实现的接口,结果与以前几乎相同。

答案 3 :(得分:0)

@Ashish Awasthi

我知道这是一个老问题,但是,我想把2便士丢进去...

如果您使用的是OOP,则正确答案(IMHO)是instanceof, method_exists。

method_exists将仅返回一个布尔值,告诉您该方法是否已定义。但是instanceof保证该方法将存在并且该方法的定义将采用预期的格式,例如:它将存在,并且该方法期望2个参数(或3个参数,或者您可能需要许多参数)已为您的方法定义)。而且,如果您使用了类型提示,那么instanceof也将确保参数(和返回值)的格式符合预期。 method_exists无法执行任何操作!