Fork me on GitHub

PHP的后期静态绑定


….

自 PHP 5.3.0 起,PHP 增加了一个叫做后期静态绑定的功能,用于在继承范围内引用静态调用的类。
当进行静态方法调用时,该类名即为明确指定的那个(通常在 :: 运算符左侧部分);当进行非静态方法调用时,即为该对象所属的类。
“后期绑定”的意思是说,static:: 不再被解析为定义当前方法所在的类,而是在实际运行时计算的。也可以称之为“静态绑定”,因为它可以用于(但不限于)静态方法的调用。

解释说明

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?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, 因为 self 关键词只能取到定义当前方法所在的类, 或者说它只能取到自己所在的那个类, 最终引用的类是A, 而不是B
好吧, 但是如果我们想要运行时最终运行的是B该如何呢?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?php
class A {
public static function who() {
echo __CLASS__;
}
public static function test() {
static::who(); // 后期静态绑定从这里开始
以上例程会输出:B}
class B extends A {
public static function who() {
echo __CLASS__;
}
}
B::test();

以上例程会输出:B

实际用法

在Laravel框架中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<?php
class Model
{
public static function create(array $attributes = [])
{
$model = new static($attributes);
$model->save();
return $model;
}
}
class Task extends Model
{
}
Task::create([
'title'=>'学习laravel',
'author'=>'pilishen'
]);

当执行Task::create()的时候,因为extends了Model,所以就到了Model里的create方法,由于$model = new static($attributes);使用了static关键词,所以此时也就相当于是执行了new Task();,也就是借助static静态绑定,我们在laravel里的自己创建的各个model,就可以共用一系列提前定义好的方法,同时在实际调用的时候,又将结果或过程只作用于自己,从而实现了一个典型的active record design pattern。

其他

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
<?php
class Father
{
public static function getSelf()
{
return new self();
}
public static function getStatic()
{
return new static();
}
}
class Son extends Father {};
echo get_class(Son::getSelf()); // Father
echo get_class(Son::getStatic()); // Son
echo get_class(Father::getSelf()); // Father
echo get_class(Father::getStatic()); // Father

http://pilishen.com/posts/php-late-static-bindings-in-laravel
http://php.net/manual/zh/language.oop5.late-static-bindings.php