后期静态绑定也就是 static::
在类中的用法,首先须要明确一点,static::
后可跟 类常量 、静态属性(类变量)、静态方法 和 普通方法(跟 类常量/静态属性/静态方法 时 static
表明一个类,跟 普通方法时 static
表明一个对象),不能够跟普通属性(对象的成员变量),由于语义上没法辨别是普通属性仍是静态属性(语法都是 static::$xx)。this
引入后期静态绑定的目的是为了打破 self::
关键词的限制,类中 self
的指向在编译时期便肯定在了代码上下文中 self
所在的类。而 static::
则是在运行时肯定其指向。在继承关系中,即可看出 self
和 static
的区别。code
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
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
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
除了代替 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