从类中静态调用实例方法

时间:2012-06-22 23:30:54

标签: php

根据其中一个手册页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进行测试

DEMO: http://codepad.viper-7.com/IKp9iX

我相信我已经证明:

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

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

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

2 个答案:

答案 0 :(得分:4)

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

这意味着我可以使用其他课程的方法'在我的班级和那些方法中假设我的班级 $ this 是他们的班级'的 $这即可。如果他们不检查InstanceOfget_class(),他们的行为将与通常完全相同。

当我像往常一样说,我的意思是他们会认为你的班级' $ this 拥有其班级所有其他方法和属性。 $ this 会有。

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

我记得这也是在C ++中工作但我无法回忆它是否只有在方法属于继承类的情况下才会起作用(尽管它们被覆盖,但是你想要访问的方法可能会被覆盖)。

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

答案 1 :(得分:2)

我会说a semi-documented feature

  

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

换句话说(据我所知),它可用于实现后期静态绑定:如果在扩展Test的某个类中调用它们,则使用self::id()static::id()可能会产生不同的结果。