我在 PHP 5.3 上遇到了问题。我需要使用 __callStatic
调用方法,但如果我在实例化对象中使用它,PHP 会改为调用 __call
。
上面是一个真实的例子:
<?php
class A {
function __call($method, $args){
// Note: $this is defined!
echo "Ops! Don't works. {$this->c}";
}
static function __callStatic($method, $args){
echo 'Fine!';
}
}
class B extends A {
public $c = 'Real Ops!';
function useCallStatic(){
static::foo();
// === A::foo();
// === B::foo();
}
}
$foo = new B();
$foo->useCallStatic();
// This works:
// B::foo();
?>
打印:糟糕!不工作。真正的行动!
请注意,我从 new B()
调用了 useCallStatic
。如果我直接调用,效果很好,如 B::foo()
。
我能做些什么让它工作正常?
最佳答案
仔细想想,还真不是bug。但这绝对是不直观的。
<?php
class A
{
public function foo()
{
static::bar();
}
public function bar()
{
echo "bar()\n";
}
}
$a = new A();
$a->foo();
这是有效的,并调用 bar()。这并不意味着静态调用 bar。意思是查找当前类名,如果存在就调用函数bar
,不管是不是静态函数。
再澄清一点:你认为 parent::bar()
意味着调用名为 bar()
的静态函数吗?不,这意味着调用任何名为 bar()
的函数。
考虑:
<?php
class A
{
function __call($name, $args)
{
echo "__call()\n";
}
static function __callStatic($name, $ags)
{
echo "__callStatic()\n";
}
function regularMethod()
{
echo "regularMethod()\n";
}
static function staticMethod()
{
echo "staticMethod()\n";
}
}
class B extends A
{
function foo()
{
parent::nonExistant();
static::nonExistant();
parent::regularMethod();
parent::staticMethod();
}
}
$b = new B();
$b->foo();
parent::nonExistant()
方法调用 A::__call()
,static::nonExistant()
也是如此。调用 A::__callStatic()
进行任一 调用同样有效! PHP 无法知道您要调用哪一个。但是,根据设计,从此类上下文调用时,PHP 赋予 __call
优先权。
parent::regularMethod()
调用非静态函数 regularMethod()
。 (同样,::
运算符并不意味着“调用此静态函数。”)同样,parent::staticMethod()
调用 A::staticMethod()
正如人们所期望的那样。
解决您的问题:
您可以在继承的类中手动调用 self::__callStatic('foo')
。
或者在 A 类的 __call
方法中过滤已知列表并调用 self::__callStatic
。
function __call($f, $a)
{
if ($f == 'foo')
return self::__callStatic($f, $a);
else
{
}
}
这很丑陋,但至少扩展类的人不需要做任何特别的事情。
关于PHP 错误地处理了我的静态调用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6181603/