后缀
后期静态绑定也就是 static::
在类中的用法,首先需要明确一点,static::
后可跟 类常量 、静态属性(类变量)、静态方法 和 普通方法(跟 类常量/静态属性/静态方法 时 static
代表一个类,跟 普通方法时 static
代表一个对象),不可以跟普通属性(对象的成员变量),因为语义上无法辨别是普通属性还是静态属性(语法都是 static::$xx)。
引入目的
引入后期静态绑定的目的是为了打破 self::
关键词的限制,类中 self
的指向在编译时期便确定在了代码上下文中 self
所在的类。而 static::
则是在运行时确定其指向。在继承关系中,便可看出 self
和 static
的区别。
使用场景
static:: 跟类常量的场景
class A {
public const FOO = 'a';
public function test() {
echo self::FOO; // self 明确指向代码上下文中所在类 A,即使被子类调用,self 也是指向 A
}
}
class B extends A {
public const FOO = 'b';
}
(new B)->test(); // 输出 a
class A {
public const FOO = 'a';
public function test() {
echo static::FOO; // static 在编译阶段不确定指向,运行时才确定指向,指向调用者,故称为 `后期绑定`。此处 static 后跟类常量,故 static 代表调用类,也就是 B 类。
}
}
class B extends A {
public const FOO = 'b';
}
(new B)->test(); // 输出 b
static:: 跟静态属性的场景(同理)
class A {
public static $foo = 'a';
public static function test() {
echo self::$foo;
}
}
class B extends A {
public static $foo = 'b';
}
B::test(); // 输出 a
class A {
public static $foo = 'a';
public static function test() {
echo static::$foo;
}
}
class B extends A {
public static $foo = 'b';
}
B::test(); // 输出 b
static:: 跟静态方法的场景
class A {
public static function who() {
echo __CLASS__; // __CLASS__ 编译时期绑定了 A 类名
}
public static function test() {
self::who(); // self 在编译时期就指向了 A 类
}
}
class B extends A {
public static function who() {
echo __CLASS__; // __CLASS__ 编译时期绑定了 B 类名
}
}
B::test(); // A
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
static:: 跟普通方法的场景
除了代替 self::
,static::
在一些场景中也可代替 $this->
。
有种场景是这样的:当父类中的方法被子类调用时,方法中的 $this-> 会首先在其所在范围(代码上下文,即父类)里寻找私有方法或属性,如果寻找不到才会调用其子类的方法或属性。而 static 属于后期绑定,可绕过这一步,直接指向方法的调用者。
class A {
private function foo() {
echo "a\n";
}
public function test() {
$this->foo(); // 所在范围中存在私有方法 foo,所以并不会调用 B 中的 foo 方法
}
}
class B extends A {
public function foo() {
echo "b\n";
}
}
(new B)->test(); // 输出 a
class A {
private function foo() {
echo "a\n";
}
public function test() {
static::foo(); // 绕过检查,直接调用调用者的该方法
}
}
class B extends A {
public function foo() {
echo "b\n";
}
}
(new B)->test(); // 输出 b
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。