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