PHP中迟到的静态绑定究竟是什么?
PHP中迟到的静态绑定究竟是什么?
从PHP 5.3.0开始,PHP实现了一个叫做后期静态绑定的特性,可以在静态inheritance的上下文中引用被调用的类。
晚期的静态绑定试图通过引入一个引用最初在运行时被调用的类的关键字来解决这个限制。 决定不引入新的关键字,而是使用已经保留的static
。
我们来看一个例子:
<?php class Car { public static function run() { return static::getName(); } private static function getName() { return 'Car'; } } class Toyota extends Car { public static function getName() { return 'Toyota'; } } echo Car::run(); // Output: Car echo Toyota::run(); // Output: Toyota ?>
late static bindings
通过存储最后一个“非转发呼叫”中指定的类来工作。 在静态方法调用的情况下,这是明确命名的类(通常是在::运算符左边的那个); 在非静态方法调用的情况下,它是对象的类。
“转发呼叫”是由self::
, parent::
, static::
,或者,如果在类层次结构forward_static_call()
引入的static::
forward_static_call()
。
函数get_called_class()
可以用来检索被调用类名称的string,并且static::
引入它的作用域。
您肯定需要阅读PHP手册中的Late Static Bindings 。 不过,我会尽量给你一个快速的总结。
基本上,归结为self
关键字不遵循inheritance规则的事实。 self
总是解决到它使用的类。 这意味着如果您在父类中创build一个方法并从一个子类调用它,那么self
就不会像您期望的那样引用该子类。
后期的静态绑定为static
关键字引入了新的用途,解决了这个特殊的缺点。 当你使用static
,它代表你第一次使用它的类,即。 它“绑定”到运行时类。
这是背后的两个基本概念。 玩static
游戏时, self
, parent
和static
操作方式可能是微妙的,所以我强烈build议你学习手册页的例子。 一旦你了解了每个关键字的基础知识,这些例子就非常有必要了解你将得到什么样的结果。
没有很明显的行为:
以下代码产生“alphabeta”。
class alpha { function classname(){ return __CLASS__; } function selfname(){ return self::classname(); } function staticname(){ return static::classname(); } } class beta extends alpha { function classname(){ return __CLASS__; } } $beta = new beta(); echo $beta->selfname(); // Output: alpha echo $beta->staticname(); // Output: beta
但是,如果我们从beta类中删除了classname函数的声明,则会得到“alphaalpha”。
我从这本书引用:“PHP大师写尖端的代码”。
后期静态绑定是php 5.3引入的一个特性。 它允许我们inheritance父类的静态方法,并引用被调用的子类。
这意味着你可以拥有一个带有静态方法的抽象类,通过使用static :: method()表示而不是self :: method()来引用子类的具体实现。
随意看看官方的PHP文档,以及: http : //php.net/manual/en/language.oop5.late-static-bindings.php
例:
<?php class Animal { public static function StaticCall() { // Parent object invokes its own getAnimalName() // Child object invokes its own getAnimalName() instead of parent's getAnimalName() return static::getAnimalName(); } public static function SelfCall() { return self::getWeight(); } private static function getAnimalName(){ return 'Animal <br />'; } private static function getWeight(){ return '10 kg <br />'; } } class Bird extends Animal { public static function getAnimalName(){ return 'Bird <br />'; } private static function getWeight(){ return '2 kg <br />'; } } echo Animal::StaticCall(); // Animal echo Animal::SelfCall(); // 10 kg echo Bird::StaticCall(); // Bird invokes method from own object echo Bird::SelfCall(); // 10 kg invokes method from parent
在上面的代码中,您可以看到两个类是父类的Animal
和是子类的Bird
。 Animal
和Bird
都有一个getAnimalName()
和getWeight()
方法。 超类Animal
有两个方法: StaticCall()
和SelfCall()
。
StaticCall()
方法使用static
关键字调用getAnimalName()
。
SelfCall()
方法使用self
关键字调用getWeight()
。
我们现在的问题是: getAnimalName()
在哪个上下文中执行?
答案是: static::getAnimalName()
标识上下文并在该上下文中调用该方法。
如果您调用Bird::StaticCall()
,代码将执行StaticCall()
。 然后static::getAnimalName()
将调用并从Bird
执行方法getAnimalName()
。
这与self::
不同,因为self::
总是调用self
中定义的对象的方法。所以如果self::getWeight()
在对象Animal
中定义SelfCall()
和Bird::SelfCall()
方法调用then self::getWeight()
在Animal
对象的上下文中调用getWeight()
。
最简单的例子来显示差异。
请注意, self :: $ c
class A { static $c = 7; public static function getVal() { return self::$c; } } class B extends A { static $c = 8; } B::getVal(); // 7
后期静态绑定,请注意static :: $ c
class A { static $c = 7; public static function getVal() { return static::$c; } } class B extends A { static $c = 8; } B::getVal(); // 8
例如:
abstract class Builder { public static function build() { return new static; } } class Member extends Builder { public function who_am_i() { echo 'Member'; } } Member::build()->who_am_i();
从“为什么我会用这个? 透视,它基本上是一种改变静态方法被解释/运行的上下文的方式。
用self
,上下文就是你最初定义方法的地方。 与static
,这是你打电话给它的人。