PHP 後期靜態綁定 ( Late Static Bindings ) 的使用

後綴

後期靜態綁定也就是 static:: 在類中的用法,首先須要明確一點,static:: 後可跟 類常量靜態屬性(類變量)靜態方法普通方法(跟 類常量/靜態屬性/靜態方法 時 static 表明一個類,跟 普通方法時 static 表明一個對象),不能夠跟普通屬性(對象的成員變量),由於語義上沒法辨別是普通屬性仍是靜態屬性(語法都是 static::$xx)。this

引入目的

引入後期靜態綁定的目的是爲了打破 self:: 關鍵詞的限制,類中 self 的指向在編譯時期便肯定在了代碼上下文中 self 所在的類。而 static:: 則是在運行時肯定其指向。在繼承關係中,即可看出 selfstatic 的區別。code

使用場景

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
相關文章
相關標籤/搜索