【问题标题】:instanceof or method_exist which one should use?instanceof 或 method_exist 应该使用哪一个?
【发布时间】:2015-02-27 14:23:46
【问题描述】:

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

我应该像这样使用instanceof

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

或者应该像这样选择method_exists

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

我很困惑。哪种方法更好。

编辑

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

【问题讨论】:

  • 您的编辑不会改变任何答案
  • @Alex 那么你的建议是什么?我应该使用 method_exist 还是两者兼而有之?你能发表你的意见吗?
  • 我已经做到了@Ali 的回答是正确的,你应该使用method_exists

标签: php function class-design instanceof


【解决方案1】:

@Ashish Awasthi

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

如果您使用的是 OOP,那么正确答案 (恕我直言) 是 instanceof,NOT method_exists。

method_exists 只会返回一个布尔值,告诉你方法是否被定义。但是 instanceof 保证该方法将存在 并且 该方法的定义将采用预期的格式,例如:它将存在,并且该方法需要 2 个参数(或 3 个,或者你有多少已为您的方法定义)。而且,如果您使用了类型提示,那么 instanceof 还将确保参数(和返回值)的格式符合预期。 method_exists 不能做任何事情!

【讨论】:

  • 感谢您的回复,但您能否添加一些示例以更清晰。提前致谢
  • 确实,method_exists 并没有告诉你任何关于对象的信息,并且给它一个字符串而不是对象甚至会尝试自动加载器。见bugs.php.net/bug.php?id=79623
【解决方案2】:

如果您正在寻找最有效的方法,那么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 可能会针对调用的特定类缓存结果 - 反射类仅检查给定类一次,无论您创建多少反射实例 - 这是性能问题,因为类实例获胜'不要在运行时更改定义,因此反射复制工作没有任何意义,会产生相同的结果。我不知道这是否适用于这种情况,但它应该适用,因为同样的规则适用。

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

不存在

事后,我再次进行了相同的检查,这次是寻找一个不存在的方法和一个未实现的接口,结果与以前几乎相同。

【讨论】:

    【解决方案3】:

    你可以做一个界面:

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

    【讨论】:

    • @Witt 请在我的问题中参考我的编辑,您会看到类已经实现了 interafce,因此检查 instanceof 就足够了。但我想知道哪种方法更好更有效。谢谢你的回答
    • 检查接口。如果它有接口,它必须有方法。这就是界面的全部概念。 method_exists 将把每个巨大的类倒过来检查方法,而instanceof 接口只需要检查一件事。做批量测试会很有趣。但我的直觉(期待 cmets)说检查 instanceof 接口应该更有效。
    • 这当然只有当您在所有要调用该方法的类中始终使用该接口时才有效……但这是适当架构的问题。我找到了性能测试here。虽然是德语。 instanceof 以微弱优势获胜,但请记住,他在测试中检查的班级并不大。
    【解决方案4】:

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

    简单测试

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

    【讨论】:

    • 如果我检查该对象是否属于某个类,那么我知道该方法存在于该类中。我只是想知道更好的方法。它们都可以在我的情况下使用。
    • 这是一种奇怪的验证方法。但我会举一个你所说的例子。假设我要去一家商店,我想检查一下我是否有钱。我会试着记住我最后一次付钱并假设我还有钱吗?还是直接检查我的钱包看看我是否真的有钱?
    • 你甚至可以使用try catch,但这并不意味着它是一个好习惯和好主意。 @Ali 答案是正确的,您应该使用 method_exists。您的论点是,如果您知道类名,就知道它具有所需的方法,就等于您了解有关代码的所有信息。因此,如果您了解有关代码的所有信息,则无需检查变量的类!你必须知道它! ;-)
    • 另外,你可以同时使用if(($obj instanceof MyClass) &amp;&amp; method_exists($obj, 'MyMethod'))
    • 请考虑我对问题的编辑,并阅读编辑部分,然后请给出您的意见。
    猜你喜欢
    • 2020-12-11
    • 1970-01-01
    • 1970-01-01
    • 2011-03-11
    • 2011-03-08
    • 2020-04-04
    • 2012-08-27
    • 1970-01-01
    • 2013-01-27
    相关资源
    最近更新 更多