PHP 中的后期静态绑定到底是什么?

PHP 中的后期静态绑定到底是什么?

49571 次浏览

您肯定需要阅读 PHP 手册中的 晚期静态绑定

基本上,归结起来就是 self关键字不遵循相同的继承规则。self总是解析为使用它的类。这意味着如果在父类中创建一个方法并从子类中调用它,self将不会像您期望的那样引用该子类。

后期静态绑定引入了 static关键字的新用法,它解决了这个特殊的缺点。当您使用 static时,它表示您首次使用它的类,即。它“绑定”到运行时类。

这是它背后的两个基本概念。当 static发挥作用时,selfparentstatic的运作方式可能是微妙的,所以与其进行更详细的讨论,我强烈建议您学习手册页示例。一旦您理解了每个关键字的基本知识,这些示例就非常有必要了解您将获得什么样的结果。

例如:

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();

来自 PHP: 后期静态绑定-手册:

从 PHP 5.3.0开始,PHP 实现了一个称为后期静态绑定的特性,可以用来在静态继承的上下文中引用被调用的类。

后期静态绑定试图通过引入引用最初在运行时调用的类的关键字来解决这个限制。... 决定不引入新的关键字,而是使用已经保留的 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
?>

后期静态绑定通过存储在最后一个“非转发调用”中命名的类来工作。对于静态方法调用,这是显式命名的类(通常是 ::操作符左边的类) ; 对于非静态方法调用,它是对象的类。“转发调用”是由 self::parent::static::引入的静态调用,如果在类层次结构中向上,则为 forward_static_call()。函数 get_called_class()可以用来检索具有被调用类名称的字符串,而 static::引入了它的作用域。

没有非常明显的行为:

下面的代码生成‘ 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引入的一个特性 Us 从父类继承静态方法,并引用 孩子们被召集起来。

这意味着您可以拥有一个具有静态方法的抽象类,并且 方法引用子类的具体实现 Static: : method () 符号代替 self: : method ()。

请随意查看官方的 php 文档: Http://php.net/manual/en/language.oop5.late-static-bindings.php


解释后期静态绑定的最清楚的方法是使用一个实例。我把它用在模板方法上。请看下面。

abstract class AbstractTemplate {
    

public const AWESOME_LIST = [''];
    

public function someFunction(): void {
$awesomeList = $this->getAwesomeList();


// OUTPUT: ['harry','henk','john'];
var_dump($awesomeList);
}




/**
* This function gets static constants from CHILD classes
*/
public function getAwesomeList(): array
{
return static::AWESOME_LIST;
}
}


class ConcreteTemplate extends AbstractTemplate {
    

public const AWESOME_LIST = ['harry','henk','john'];
    

public function someFunction(): void {
parent::someFunction();
}
}


$concreteTemplate = new ConcreteTemplate();
$concreteTemplate->someFunction();

注意方法 getAwesomeList中的 static关键字。 现在让我们改变一下:

public function getAwesomeList(): array
{
return self::AWESOME_LIST;
}

someFunctionvar_dump输出为:

array (size=1)
0 => string '' (length=0)

在 Singleton 设计模式中使用 static关键字。 参见链接: < a href = “ https://refactoring.guru/design-pattern/singleton/php/example”rel = “ nofollow norefrer”> https://refactoring.guru/design-patterns/singleton/php/example

从“我为什么要用这个?”透视图中,它基本上是一种更改静态方法解释/运行的上下文的方法。

对于 self,上下文是最初定义方法的上下文。有了 static,你就可以用它打电话了。

显示差异的最简单示例。
注意,< strong > self: : $c

class A
{
static $c = 7;


public static function getVal()
{
return self::$c;
}
}


class B extends A
{
static $c = 8;
}


B::getVal(); // 7

后期静态绑定,注意 静态: : $c

class A
{
static $c = 7;


public static function getVal()
{
return static::$c;
}
}


class B extends A
{
static $c = 8;
}


B::getVal(); // 8

此外,还要注意是否更新了子类中的静态变量。在孩子 B 更新孩子 C 时,我发现了这个(有点)意想不到的结果:

class A{
protected static $things;
}


class B extends A {
public static function things(){
static::$things[1] = 'Thing B';
return static::$things;
}
}


class C extends A{
public static function things(){
static::$things[2] = 'Thing C';
return static::$things;
}
}


print_r(C::things());
// Array (
//   [2] => Thing C
// )


B::things();


print_r(C::things());
// Array (
//    [2] => Thing C
//    [1] => Thing B
// )

您可以通过在每个子类中声明相同的变量来修复它,例如:

class C extends A{
protected static $things; // add this and B will not interfere!


public static function things(){
static::$things[2] = 'Thing C';
return static::$things;
}
}