PHP-后期静态绑定-Late-Static-Bindings-的使用

30次阅读

共计 1835 个字符,预计需要花费 5 分钟才能阅读完成。

后缀

后期静态绑定也就是 static:: 在类中的用法,首先需要明确一点,static:: 后可跟 类常量 静态属性(类变量)静态方法 普通方法 (跟 类常量 / 静态属性 / 静态方法 时 static 代表一个类,跟 普通方法时 static 代表一个对象), 不可以跟普通属性(对象的成员变量),因为语义上无法辨别是普通属性还是静态属性(语法都是 static::$xx)。

引入目的

引入后期静态绑定的目的是为了打破 self:: 关键词的限制,类中 self 的指向在编译时期便确定在了代码上下文中 self 所在的类。而 static:: 则是在运行时确定其指向。在继承关系中,便可看出 selfstatic 的区别。

使用场景

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

正文完
 0