如何检测静态函数非静态调用?
例如,在这种情况下:
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']
没有告诉我们(在这两种情况下都是::
。)
答案 0 :(得分:2)
解决方案有两个方面:
首先需要停用E_STRICT
报告:
error_reporting(error_reporting() ^ E_STRICT);
下一个应该从函数声明中删除static
关键字。
public /* static */ function bar()
现在可以在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
,他很快会被告知他犯了错误。