为什么PHP更喜欢使用__call()而不是__callStatic()?

6

当我尝试这个:

<?php
class myParent {
    public function __call($method, $params) {
        echo "from __call";
    }

    public function __callStatic($method, $params) {
        echo "from __callStatic";
    }
}

class mySon extends myParent {
    public function bar() {
        myParent::foo();
    }
}

(new mySon())->bar();

我期望得到这个输出:from __callStatic ...,但实际上输出为:from __call。有人能解释一下原因吗?
编辑:确切地说,我想知道如果我删除__call函数,那么它会触发__callStatic,是否有办法在声明__call时触发__callStatic

(new mySon())是一个对象。您在该对象上调用了方法bar(),该方法为对象的父类调用了foo(),该父类是该对象本身的一部分。在任何时候,它都不会对任何静态引用进行操作。 - kainaw
如果你移除extends myParent- 你将得到你需要的结果,因为类之间不再有关联。 - u_mulder
3个回答

4

这里发生了两件事情,首先:PHP支持classname::method作为parent::method的一个别名,并且可以跳过树中的某些类就像这里演示的那样

其次,parent::不是静态调用,使用parent::classname::都无法静态调用父级方法。我曾经提交过一个错误报告,但这并没有引起任何开发人员对此进行改进。

这两者结合起来导致了您看到的非直观行为。


3
您是在类的实例内部以静态方式调用了该函数。因此,PHP会调用基于实例的__call()方法。请注意,此代码在功能上等效于您静态编写的内容。
class mySon extends myParent {
    public function bar() {
        $this->foo(); // works the same way as myParent::foo();
    }
}

如果您按照以下方式调用它,您将获得静态的结果(请注意,__callStatic()本身必须是静态的)
class myParent {
    public function __call($method, $params) {
        echo "from __call";
    }

    public static function __callStatic($method, $params) {
        echo "from __callStatic";
    }
}
myParent::foo();

但是为什么当我删除__call函数时,就会调用__callStatic函数呢? 我能否以某种方式从bar()函数中触发__callStatic函数? - Jules Lamur
@JohnSaucisse 如其他评论所述,如果您删除“extends”关键字,则该类将不再是您尝试静态调用的类的实例。至于为什么没有“__call”方法就会调用“__callStatic”方法,这可能与操作顺序有关。 - Machavity

1

好的,我找到了一个明显的解决方案来完成我想要做的事情:

class mySon extends myParent {
    public function bar() {
        myParent::__callStatic('foo', array());
    }
}

2
你问了“为什么”,这已经被解释了。绕过问题并不解释原因,因此不是对问题的有效回答。 - Sjon

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接