PHP的Calling Scope

今天看陌生人代碼發現,:: 可以調用類的非靜態方法
開始懷疑我自己。
然後發現了鳥哥的這篇文章。

php中__call和__callstatic在被繼承後會怎樣?

這個問題乍看, 確實很容易讓人迷惑, 但實際上, 造成這樣的誤解的根本原因在於: 在PHP中, 判斷靜態與否不是靠”::”(PAAMAYIM_NEKUDOTAYIM)符號, 而是靠calling scope.

那麼, 什麼是calling scope?

在PHP中, 調用一個方法的時候, $this指針指向的對象就是這個方法被調用時刻的calling scope. 對於下面的例子:

<?php
Foo::bar();
?>

在調用bar方法的時候, 處於一個沒有calling scope域的上下文中, 所以這個是靜態調用.

而對於如下的例子:

<?php
class A {
     public function test() {
         Foo::bar();
     }
 }
$a  = new A();
$a->test();

在調用bar方法的時候, 處於一個$a對象的上下文中, 也就是說, 此時的calling scope是$a對象, 所以這個其實不是靜態調用.

爲了驗證這一個結論, 請看下面的一個實際例子:

<?php
 class Foo {
     public function bar() {
         var_dump($this);
     }
 }
 class A {
     public function test() {
         Foo::bar();
     }
 }
 $a  = new A();
 $a->test();
?>

輸出什麼呢?

object(A)#1 (0) {
}

在調用bar的時候, 這個看似”靜態”調用的調用, $this指針卻是被賦值的, 指向的是$a對象, 那麼這個還算靜態調用麼?

我舉這個例子是爲了說明這個問題, 但大家在實際的應用中, 大家儘量要避免使用”::”來調用一個非靜態的方法, PHP也會對於這種調用給出一個Strict 警告:

Strict Standards: Non-static method Foo::bar() should not be called statically, assuming $this from incompatible context

也許有人會說這個應該算bug吧? 其實不然, 更多的應該是錯誤使用造成的, 因爲你在一個有calling scope的上下文中採用”靜態的形式”調用了一個類的非靜態方法所致.

那麼PHP爲什麼要這麼設計呢? 考慮下面的例子:

<?php
 class A {
    public function __construct() {
    }
 }
  class B extends A {
    public function __construct() {
        parent::__construct();
   }
   }

當我們調用父類的構造函數的時候, 我們是有意的要把當前的scope傳遞給父類的構造函數作爲calling scope的.

發佈了63 篇原創文章 · 獲贊 24 · 訪問量 8萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章