检测非静态调用的静态函数

时间:2016-10-31 01:43:37

标签: php

如何检测静态函数非静态调用?

例如,在这种情况下:

class Foo
{
    public static function bar()
    {
        // How can I tell here that bar() is called on an instance?

        //var_dump(debug_backtrace()[0]['type'] == '::');
        // at all times the above prints bool(true)
        return 1;
    }
}

// later in the code
$foo = new Foo();
$foo::bar(); // that's fine

// even later
$foo->bar(); // this should not happen, yet it's here and there

我想调试和根除上面最后一行的情况:有人在某个地方错误地调用某个实例上的函数,期望它会返回与主题中的实例相关的内容;而是一个得到一个有点相关的常数。随后我需要知道这种情况何时发生。如果地狱破裂或异常被抛出也很好。

到目前为止,我发现静态函数的非静态调用是internally translated into static calls,因此debug_backtrace()[0]['type']没有告诉我们(在这两种情况下都是::。)

2 个答案:

答案 0 :(得分:2)

解决方案有两个方面:

  1. 首先需要停用E_STRICT报告:

    error_reporting(error_reporting() ^ E_STRICT);
    
  2. 下一个应该从函数声明中删除static关键字。

    public /* static */ function bar()
    
  3. 现在可以在debug_backtrace函数的帮助下查看是静态还是动态调用函数:

    class Foo
    {
        public function bar()
        {
            $calledStatically = debug_backtrace()[0]['type'] == '::';
    
            if (!$calledStatically) {
                throw new Exception("Should not happen");
            }
    
            // ...
        }
    }
    

    来自文档:

      

    type(字符串):当前的呼叫类型。如果是方法调用,“ - >”退回。如果是静态的   方法调用,返回“::”。如果是函数调用,则什么都没有   返回。

    快速演示。

    Foo::bar(); // normal result returned
    
    $foo = new Foo();
    $foo->bar(); // throws exception
    

答案 1 :(得分:0)

如果你不想永远关掉E_STRICT,那就有办法了。

如果班级Foo是纯粹的运气或天意,只能在几个地方实例化:

public function getFoo()
{
    return new Foo();
}

然后,如果我们将其子类化并重新定义bar()

class Foo2 extends Foo
{
    public static function bar()
    {
         throw new Exception("You're calling Foo::bar() on an instance");
    }
}

然后,如果我们将Foo替换为实例化的Foo2 ......

public function getFoo()
{
    //return new Foo();
    return new Foo2();
}

调用上面的新静态方法时会抛出异常:

$q = Foo::bar(); // no error just as before

$foo = $other->getFoo();
$foo->bar(); // throws exception

如果有人曾经$foo->bar();发送Foo,他很快会被告知他犯了错误。