5

根据手册页之一http://www.php.net/manual/en/language.oop5.static.php

静态调用非静态方法会生成 E_STRICT 级别的警告。

但是,当从类内部进行调用时,情况似乎并非如此:

error_reporting(-1);

class Test {
    private $id;
    function __construct($id) { $this->id = $id; }
    function id() { return $this->id; }

    function __toString() {
        return Test::id()
             . self::id()
             . static::id()
             . static::id()
             . call_user_func('Test::id')
             . call_user_func(array('Test', 'id'));
    }
}
$a = new Test('a');
$b = new Test('b');


echo "$a $b $a"; # aaaaaa bbbbbb aaaaaa
var_dump(error_get_last()); # NULL

使用 php 5.4 进行测试

演示: http ://codepad.viper-7.com/IKp9iX

我相信我已经证明:

  • 不生成 E_STRICT 警告
  • 该php神奇地将静态方法调用更正为实例方法调用(访问实例变量id证明了这一点)。

编辑- 我想补充一点,将debug_backtrace () 插入到 __toString 调用中会产生一个调用“类型” ->,这意味着“方法调用”。

这是一个错误,还是记录在案的功能?

4

2 回答 2

5

如果您在任何类(不仅仅是声明类)中使用静态语法调用非静态函数,则该非静态函数的行为就像在当前$this对象的上下文中调用它一样。

这意味着我可以在我的班级中使用来自其他班级的方法,并且这些方法将假定我班级的$this是他们的班级' $this。如果他们不检查,InstanceOf或者get_class()他们的行为将与往常完全相同。

当我像往常一样说时,我的意思是他们会假设您的类' $this具有他们的类' $this将具有的所有其他方法和属性。

这(我认为)称为对象上下文绑定。在 JavaScript 中,您必须使用这些call()和/或apply()方法来使函数表现得好像它附加到某个对象一样。但在 PHP 中,它只是通过在非静态函数上使用静态语法来工作。

我记得这在 C++ 中也有效,但我不记得它是否仅在方法属于继承类时才有效(可能是您想要访问的被覆盖的方法,尽管它们被覆盖)。

使用这个(隐藏的)特性,您可以实现装饰器设计模式,通过该模式在运行时向对象添加新功能。您还可以模拟MixinsTraits(PHP 5.4 现在原生支持),额外的好处是此实现在运行时处理,因此可以动态完成/撤消,而不是在编译时处理的语言功能实现并且不能动态完成/撤消,您必须更改代码才能更改功能。

于 2012-06-22T23:43:05.417 回答
2

我会说这是一个半文档化的功能

在非静态上下文中,被调用的类将是对象实例的类。由于 $this-> 将尝试从同一范围调用私有方法,因此使用 static:: 可能会产生不同的结果。另一个区别是 static:: 只能引用静态属性。

换句话说(据我所知),它可以用来实现后期静态绑定:如果你在扩展你的测试的某个类中调用它们,使用self::id()and可能会给出不同的结果。static::id()

于 2012-06-22T23:38:27.203 回答