自 PHP 5.3.0 起,PHP 增加了一个叫做后期静态绑定的功能,用于在继承范围内引用静态调用的类。准确说,后期静态绑定工作原理是存储了在上一个“非转发调用”的类名。当进行静态方法调用时,该类名即为明确指定的那个(通常在 :: 运算符左侧部分);当进行非静态方法调用时,即为该对象所属的类。
该功能从语言内部角度考虑被命名为“后期静态绑定”。“后期绑定”的意思是说,static::
不再被解析为定义当前方法所在的类,而是在实际运行时计算的。也可以称之为“静态绑定”,因为它可以用于(但不限于)静态方法的调用。
使用 self:: 或者 __CLASS__
对当前类的静态引用,取决于定义当前方法所在的类:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
<?php
class A {
public static function who () {echo __CLASS__ ;}
public static function test () {self :: who ();}
}
class B extends A {
public static function who () {echo __CLASS__ ;}
}
B :: test ();
?>
以上例程会输出: A
后期静态绑定
<?php
class A {
public static function who () {echo __CLASS__ ;}
public static function test () {
static:: who (); // 后期静态绑定从这里开始
}
}
class B extends A {
public static function who () {echo __CLASS__ ;}
}
B :: test ();
?>
|
该例会输出: B
我们都知道静态方法还可以用作工厂方法,下面给大家看一个代码实例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
<?php
Class Parent {
//父类的一些方法...
}
Class One extends Parent {
Static Public function _create () {
return new One();
}
}
Class Two extends Parent {
Static Public function _create () {
return new Two();
}
}
//......
print_r(One::_create());
print_r(Two::_create());
?>
|
在上面的父类Parent当中包含了很多的功能可被扩展类所调用,但是,他的两个派生类在创建自己的对象时使用了大量的重复代码,这是我们所不能忍受的,因为大量的重复代码很烦人也说明了你不是一个合格的coder。
笔者一直都坚信:简单的就是最好的。那么我们能不能把_create()方法放在父类当中被公共使用呢?
来看下面的实例:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
<?php
Class Parent {
//父类的一些方法...
Static Public function _create () {
return new self();
}
}
Class One extends Parent {}
Class Two extends Parent {}
//......
print_r(One::_create());
print_r(Two::_create());
?>
|
这样仿佛我们就解决问题了,但是,由结果我们可以看出,并不是我们想要的One和Two类的实例对象,而是父类的实例,怎么回事呢?
因为self指的不是调用上下文,而是解析上下文。因此,self被解析为定义_create()方法的Parent类。而不是解析为调用_create方法的One和Two类的实例对象。
但是,在PHP中引入了延迟静态绑定机制,其实就是使用static关键字。而static类似于self和parent,但他指的是被调用的类不是包含类。
下面,我们来使用static进行改进:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
<?php
Class Parent {
//父类的一些方法
Static Public function _create () {
//这里使用static延迟静态绑定关键字static
return new static();
}
}
Class One extends Parent {}
Class Two extends Parent {}
//......
print_r(One::_create());
print_r(Two::_create());
?>
|
由打印结果可以看出,确实生成了One和Two类的实例化对象,是不是省去了很多的重复代码,static确实很好用. :)