PHP 5.3 引入 靜態延遲綁定,透過 static:: 關鍵字解決繼承體系中靜態方法無法正確引用子類別的問題。本文透過範例逐步揭示 self:: 的侷限性,並展示 static:: 的強大用法。
self:: 綁定的是定義該方法的類別(解析上下文),而非實際調用的類別(調用上下文)。
abstract class U {
public static function create() {
return new self(); // 編譯時綁定到 U
}
}
class u1 extends U {}
class u2 extends U {}
u1::create(); // Fatal error: Cannot instantiate abstract class U
此處 self 指向 U,導致嘗試實例化抽象類別而報錯。
static:: 在執行時解析為實際調用的類別(u1 或 u2)。
abstract class U {
public static function create() {
return new static(); // 執行時綁定到調用類別
}
}
class u1 extends U {}
class u2 extends U {}
$obj1 = u1::create(); // 產生 u1 實例
$obj2 = u2::create(); // 產生 u2 實例
static:: 不限於實例化,也可用於靜態方法調用、屬性存取,甚至在建構子等非靜態方法中:
abstract class U {
private $group;
public function __construct() {
$this->group = static::getGroup(); // 延遲綁定到子類別
}
public static function create() {
return new static();
}
static function getGroup() {
return 'default';
}
}
class u1 extends U {}
class u2 extends U {
static function getGroup() { return 'u2'; }
}
class u3 extends u2 {}
print_r(u1::create()); // u1 Object ( [group:U:private] => default )
print_r(u3::create()); // u3 Object ( [group:U:private] => u2 )
u1 未覆寫 getGroup(),繼承父類別預設值 default。u3 繼承 u2 的 getGroup(),返回 u2。| 關鍵字 | 綁定時機 | 指向 | 適用場景 |
|---|---|---|---|
self:: | 編譯時(定義時) | 當前定義類別 | 存取當前類別的常數、靜態屬性/方法,不希望被子類別覆寫 |
static:: | 執行時(調用時) | 實際調用類別 | 工廠模式、Template Method 模式、需子類別自訂行為的靜態調用 |
parent:: | 編譯時 | 父類別 | 明確調用父類別實作 |
static::。self:: 略微提升效能(極微小)。static:: 方法中直接存取 $this(非靜態上下文除外)。延遲靜態綁定是 PHP 物件模型成熟的關鍵一步,讓靜態方法也能享有多態優勢。善用 static::,能寫出更彈性、可復用的基類架構。