<?php class A { public static function foo() { echo __CLASS__."\n"; static::who(); } public static function who() { echo __CLASS__."\n"; } } class B extends A { public static function test() { echo "A::foo()\n"; A::foo(); echo "parent::foo()\n"; parent::foo(); echo "self::foo()\n"; self::foo(); } public static function who() { echo __CLASS__."\n"; } } class C extends B { public static function who() { echo __CLASS__."\n"; } } C::test(); /* * C::test(); //非转发调用 ,进入test()调用后,“上一次非转发调用”存储的类名为C * * //当前的“上一次非转发调用”存储的类名为C * public static function test() { * A::foo(); //非转发调用, 进入foo()调用后,“上一次非转发调用”存储的类名为A,然后实际执行代码A::foo(), 转 0-0 * parent::foo(); //转发调用, 进入foo()调用后,“上一次非转发调用”存储的类名为C, 此处的parent解析为A ,转1-0 * self::foo(); //转发调用, 进入foo()调用后,“上一次非转发调用”存储的类名为C, 此处self解析为B, 转2-0 * } * * * 0-0 * //当前的“上一次非转发调用”存储的类名为A * public static function foo() { * static::who(); //转发调用, 因为当前的“上一次非转发调用”存储的类名为A, 故实际执行代码A::who(),即static代表A,进入who()调用后,“上一次非转发调用”存储的类名依然为A,因此打印 “A” * } * * 1-0 * //当前的“上一次非转发调用”存储的类名为C * public static function foo() { * static::who(); //转发调用, 因为当前的“上一次非转发调用”存储的类名为C, 故实际执行代码C::who(),即static代表C,进入who()调用后,“上一次非转发调用”存储的类名依然为C,因此打印 “C” * } * * 2-0 * //当前的“上一次非转发调用”存储的类名为C * public static function foo() { * static::who(); //转发调用, 因为当前的“上一次非转发调用”存储的类名为C, 故实际执行代码C::who(),即static代表C,进入who()调用后,“上一次非转发调用”存储的类名依然为C,因此打印 “C” * } */ 故最终结果为: A::foo() A A parent::foo() A C self::foo() A C
3.更多静态后期静态绑定的例子
a)Self, Parent 和 Static的对比
<?php class Mango { function classname(){ return __CLASS__; } function selfname(){ return self::classname(); } function staticname(){ return static::classname(); } } class Orange extends Mango { function parentname(){ return parent::classname(); } function classname(){ return __CLASS__; } } class Apple extends Orange { function parentname(){ return parent::classname(); } function classname(){ return __CLASS__; } } $apple = new Apple(); echo $apple->selfname() . "\n"; echo $apple->parentname() . "\n"; echo $apple->staticname(); ?> 运行结果: Mango Orange Apple
b)使用forward_static_call()
<?php class Mango { const NAME = 'Mango is'; public static function fruit() { $args = func_get_args(); echo static::NAME, " " . join(' ', $args) . "\n"; } } class Orange extends Mango { const NAME = 'Orange is'; public static function fruit() { echo self::NAME, "\n"; forward_static_call(array('Mango', 'fruit'), 'my', 'favorite', 'fruit'); forward_static_call('fruit', 'my', 'father\'s', 'favorite', 'fruit'); } } Orange::fruit('NO'); function fruit() { $args = func_get_args(); echo "Apple is " . join(' ', $args). "\n"; } ?> 运行结果: Orange is Orange is my favorite fruit Apple is my father's favorite fruit
c)使用get_called_class()
<?php class Mango { static public function fruit() { echo get_called_class() . "\n"; } } class Orange extends Mango { // } Mango::fruit(); Orange::fruit(); ?> 运行结果: Mango Orange
应用
前面已经提到过了,引入后期静态绑定的目的是:用于在继承范围内引用静态调用的类。
所以, 可以用后期静态绑定的办法解决单例继承问题。
先看一下使用self是一个什么样的情况:
<?php // new self 得到的单例都为A。 class A { protected static $_instance = null; protected function __construct() { //disallow new instance } protected function __clone(){ //disallow clone } static public function getInstance() { if (self::$_instance === null) { self::$_instance = new self(); } return self::$_instance; } } class B extends A { protected static $_instance = null; } class C extends A{ protected static $_instance = null; } $a = A::getInstance(); $b = B::getInstance(); $c = C::getInstance(); var_dump($a); var_dump($b); var_dump($c); 运行结果: E:\code\php_test\apply\self.php:37: class A#1 (0) { } E:\code\php_test\apply\self.php:38: class A#1 (0) { } E:\code\php_test\apply\self.php:39: class A#1 (0) { }
通过上面的例子可以看到,使用self,实例化得到的都是类A的同一个对象
再来看看使用static会得到什么样的结果