php延迟静态绑定

问题背景

某天。新来的小A问了我一个问题 :子类重载了父类的方法,父类如何调用呢?

案例


<?php
class base{

}
class aClass extends base{
    public static function create(){
        return new aClass();
    }
}
class bClass extends base{
    public static function create(){
        return new bClass();
    }
}
var_dump(aClass::create());//object(aClass)#1 (0) { }
var_dump(bClass::create());//object(bClass)#1 (0) { }

?>

遵循面向对象的思想,子类重复的代码应该放在父类中实现,于是改进后:

<?php

class base{
    public static function create(){
        return new self();
    }
}
class aClass extends base{

}
class bClass extends base{

}
var_dump(aClass::create());
var_dump(bClass::create());

输出:
object(base)#1 (0) { }
object(base)#1 (0) { }

?>

显然,改进后的代码没有如我们所料。
原来父类中的self被解析为base这个父类,而不是解析成它的子类。
为了解决这个问题,php5.3引入了延迟静态绑定

延迟静态绑定

针对以上案例做改变:

<?php
class base{
    public static function create(){
        return new static();
    }
}
class aClass extends base{

}
class bClass extends base{

}
var_dump(aClass::create());//object(aClass)#1 (0) { } 
var_dump(bClass::create());//object(bClass)#1 (0) { }
?>

有意思的案例

<?php

class A {
    public static function foo() {
        static::who();
    }

    public static function who() {
        echo __CLASS__."\n";
    }
}

class B extends A {
    public static function test() {
        A::foo();
        parent::foo();
        self::foo();
    }

    public static function who() {
        echo __CLASS__."\n";
    }
}
class C extends B {
    public static function who() {
        echo __CLASS__."\n";
    }
}

C::test();
?>


输出:
A
C
C

A::foo()得到的结果是毫无疑问的,但是parent::foo()和self::foo()得到的结果就有点匪夷所思了。
而官方也只给出一句解释而已:
后期静态绑定的解析会一直到取得一个完全解析了的静态调用为止。另一方面,如果静态调用使用 parent:: 或者 self:: 将转发调用信息。

看起来不知所云,于是我做了一些测试来理解:
首先,parent:: 和 self::各自解析为什么?
我把test()方法改了一下,让他们去调用自己的who()方法:

class B extends A {
    public static function test() {
        parent::who();//result:A
        self::who();//result:B
    }
}

parent::和self::是属于静态绑定,在编译期就确定了解析对象是谁。如self::就解析为自身B,而parent::就解析为自身的父类A。
而static::可以理解为是一种动态绑定,即在编译期无法确定解析对象是谁,只有到运行期才计算出解析的对象是谁。

按照以上的说法,A::foo()和B::foo()也不能得到C的结果?
这就得重新翻翻手册:

1.后期静态绑定本想通过引入一个新的关键字表示运行时最初调用的类来绕过限制。最终决定不引入新的关键字,而是使用已经预留的 static 关键字。
2.如果静态调用使用 parent:: 或者 self:: 将转发调用信息。

也就是说静态调用使用parent::或者self::时,他们会附带一个信息来告诉static::说,运行时最初调用的类是C,这也就是转发调用(转发最初调用者的信息)

验证方法:可以用get_called_class()来检查最初调用的类是谁?
修改后代码如下:

<?php
class A {
    public static function foo() {
        static::who();
    }

    public static function who() {
        var_dump(get_called_class());
    }
}

class B extends A {
    public static function test() {
        A::foo();
        parent::foo();
        self::foo();
    }

    public static function who() {
        var_dump(get_called_class());
    }
}
class C extends B {
    public static function who() {
        var_dump(get_called_class());
    }
}

C::test();
?>



运行结果:

string(1) "A" 
string(1) "C" 
string(1) "C"

在这里还有一个疑问:如果C类里没有who()方法,那static::会解析成谁?

<?php
class A {
    public static function foo() {
        static::who();
    }

    public static function who() {
        echo __CLASS__;
    }
}

class B extends A {
    public static function test() {
        A::foo();
        parent::foo();
        self::foo();
    }

    public static function who() {
        echo __CLASS__;
    }
}
class C extends B {

}

C::test();
?>

运行结果:

A
B
B

我们看看原先的官方解释:

后期静态绑定的解析会一直到取得一个完全解析了的静态调用为止。

也就是说,虽然运行期static::得到最初调用的类来自C,但是C中并没有who()方法,于是就去找C的父类B,B有who()方法,所以static::就解析为B

请关注我的订阅号

订阅号.png

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

码哥说

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值