PHP 靜態方法不僅是「不需實例化即可呼叫」那麼簡單。當靜態方法被不同類別呼叫時,$this 的指向會隨呼叫上下文改變,這是 PHP 獨特的「晚期靜態綁定」行為。本文透過實例解析此機制與最佳實踐。
<?php
class TestClass1 {
public $normal_v = 'normal_v from TestClass1';
public static $STATIC_V = 'STATIC_V from TestClass1';
public function test_func1() {
echo $this->normal_v . '<br>' . self::$STATIC_V;
}
}
class TestClass2 {
public $normal_v = 'normal_v from TestClass2';
public static $STATIC_V = 'STATIC_V from TestClass2';
public function test_func2() {
// 靜態呼叫 TestClass1 的非靜態方法
TestClass1::test_func1();
}
}
$t2 = new TestClass2();
$t2->test_func2();
// 輸出結果:
// normal_v from TestClass2
// STATIC_V from TestClass1
?>
| 存取方式 | 綁定對象 | 說明 |
|---|---|---|
$this->normal_v | 呼叫者實例 (TestClass2) | 非靜態屬性,依執行上下文的 $this 決定 |
self::$STATIC_V | 定義類別 (TestClass1) | self 為編譯期綁定,指向寫代碼時所在類別 |
static::$STATIC_V | 呼叫類別 (TestClass2) | static 為執行期綁定(晚期靜態綁定,PHP 5.3+) |
static 的方法,若未使用 $this,可靜態呼叫(但會觸發 E_DEPRECATED 警告)。$this 保留呼叫者的實例,self 指向定義類,static 指向呼叫類。$this:除非被物件實例以 -> 呼叫,否則 $this 未定義。static 才能在靜態方法中用 self:: 或 static:: 存取。<?php
// 錯誤:靜態方法存取非靜態屬性
class Bad {
public $val = 1;
public static function get() { return self::$val; } // Fatal error
}
// 正確:屬性宣告 static
class Good {
public static $val = 1;
public static function get() { return self::$val; }
}
// 晚期靜態綁定應用:Factory 模式
class Base {
public static function create() {
return new static(); // 依呼叫類別實例化
}
}
class ChildA extends Base {}
class ChildB extends Base {}
$a = ChildA::create(); // 產生 ChildA 實例
$b = ChildB::create(); // 產生 ChildB 實例
?>
$this 依賴呼叫上下文,降低可讀性與測試性。static 回傳型別宣告,強化型別安全。