PHP中最新的静态绑定到底是什么?


Answers:


198

您肯定需要阅读PHP手册中的Late Static Bindings。不过,我将尝试给您一个简短的摘要。

基本上,可以归结为以下事实:self关键字不遵循相同的继承规则。 self始终解析为使用它的类。这意味着,如果您在父类中创建方法并从子类中调用该方法,self则不会像您期望的那样引用该子项。

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

这些是其背后的两个基本概念。的方式selfparentstatic当操作static是在打法可以是细微的,因此而不是更详细的旅途中,我强烈建议你学习手册页的例子。一旦您了解了每个关键字的基础知识,这些示例就非常有必要,以了解您将获得什么样的结果。


我发现这篇文章非常有用且具有描述性,请查看[link](techflirt.com/tutorials/oop-in-php/late-static-binding.html
Sadegh Shaikhi

“ ... self关键字不遵循继承规则。self始终解析为使用该关键字的类。” -这并不意味着您不能self像通过非静态方法那样通过子对象调用父对象的静态方法。您可能是对的,但您应该重新措辞。只有当孩子具有相同名称的成员时,这才真正重要,因为您可以通过使用其来决定引用哪些成员static::
DanMan '18

81

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
?>

后期静态绑定通过存储上一个“非转发调用”中命名的类来工作。在静态方法调用的情况下,这是显式命名的类(通常是::运算符左侧的类);在非静态方法调用的情况下,它是对象的类。A“转发呼叫”是通过引入一个静态self::parent::static::,或者,如果在类层次结构往上走,forward_static_call()。该函数get_called_class()可用于检索具有被调用类名称的字符串并static::介绍其范围。


1
这篇文章是php.net文章的逐字副本,约80%没有引用标记。
WoodrowShigeru

22

行为不是很明显:

以下代码产生“ 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类中删除类名函数的声明,则结果为'alphaalpha'。


1
非常好。PHP手册中也显示了相同的内容,但这更加清楚。供参考:php.net/manual/en/language.oop5.late-static-bindings.php(请参阅示例 4)
musicin3d

11

我从书中引用:“ PHP Master写最前沿的代码”。

后期静态绑定是php 5.3引入的功能。它允许我们从父类继承静态方法,并引用被调用的子类。

这意味着您可以使用静态方法创建一个抽象类,并通过使用引用子类的具体实现。 static :: method()表示法而不是self :: method()来。

随时查看官方php文档: http //php.net/manual/en/language.oop5.late-static-bindings.php


解释后期静态绑定的最清晰方法是一个简单的示例。看一下下面的两个类定义,然后继续阅读。

class Vehicle {
    public static function invokeDriveByStatic() {
        return static::drive(); // Late Static Binding
    }
    public static function invokeStopBySelf() {
        return self::stop(); // NOT Late Static Binding
    }
    private static function drive(){
        return "I'm driving a VEHICLE";
    }
    private static function stop(){
        return "I'm stopping a VEHICLE";
    }
}

class Car extends Vehicle  {
    protected static function drive(){
        return "I'm driving a CAR";
    }
    private static function stop(){
        return "I'm stopping a CAR";
    }
}

我们看到一个父类(车辆)和一个子类(汽车)。父类有两种公共方法:

  • invokeDriveByStatic
  • invokeStopBySelf

父类还具有2个私有方法:

  • drive
  • stop

子类将覆盖2个方法:

  • drive
  • stop

现在让我们调用公共方法:

  • invokeDriveByStatic
  • invokeStopBySelf

问自己:哪个类调用invokeDriveByStatic/ invokeStopBySelf?父母还是孩子班?

看下面:

// This is NOT Late Static Binding
// Parent class invokes from Parent. In this case Vehicle.
echo Vehicle::invokeDriveByStatic(); // I'm driving a VEHICLE
echo Vehicle::invokeStopBySelf(); // I'm stopping a VEHICLE

// !!! This is Late Static Binding !!!!
// Child class invokes an inherited method from Parent.
// Child class = Car, Inherited method = invokeDriveByStatic().
// The inherited method invokes a method that is overridden by the Child class.
// Overridden method = drive()
echo Car::invokeDriveByStatic(); // I'm driving a CAR

// This is NOT Late Static Binding
// Child class invokes an inherited method from Parent.
// The inherited method invokes a method inside the Vehicle context.
echo Car::invokeStopBySelf(); // I'm stopping a VEHICLE

所述static关键字出现在Singleton设计图案中使用。参见链接:https : //refactoring.guru/design-patterns/singleton/php/example


7

显示差异的最简单示例。
注意,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

4

例如:

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

4

从“我为什么要使用它?”看它 从角度来看,它基本上是一种更改上下文的方式,从该上下文中可以解释/运行静态方法。

使用self,上下文是您最初定义方法的地方。使用static,它就是您从中调用它的那个。


1

另外,请注意是否在子类中更新静态变量。我发现了这个(某种程度上)意外的结果,其中子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;        
    }
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.