PHP 5.3 引入靜態延遲綁定,static:: 關鍵字徹底改變了繼承中靜態成員的調用語義。本文通過最小化代碼演示核心差異,並給出選型原則。
| 關鍵字 | 綁定時機 | 解析目標 | 典型場景 |
|---|---|---|---|
self:: | 編譯期 (早期綁定) | 當前定義類 (寫代碼時所在類) | 內部實現細節、不希望被子類覆寫 |
static:: | 運行期 (延遲綁定) | 實際調用類 (誰調用就解析誰) | 可擴展的工廠方法、ActiveRecord 查詢、模板方法模式 |
<?php
class Car {
public static function model() {
self::getModel(); // 編譯期鎖定 Car::getModel
}
protected static function getModel() {
echo "This is a Car model\n";
}
}
class Taxi extends Car {
protected static function getModel() {
echo "This is a Taxi model\n";
}
}
Car::model(); // This is a Car model
Taxi::model(); // This is a Car model ← 子類調用父類方法,self 仍指向父類
<?php
class Car {
public static function model() {
static::getModel(); // 運行期解析:誰調用 model() 就用誰的 getModel
}
protected static function getModel() {
echo "This is a Car model\n";
}
}
class Taxi extends Car {
protected static function getModel() {
echo "This is a Taxi model\n";
}
}
Car::model(); // This is a Car model
Taxi::model(); // This is a Taxi model ← 動態綁定生效
abstract class Model {
protected static string $table = '';
// 靜態工廠:動態綁定獲取子類表名
public static function find(int $id): ?static {
$table = static::$table; // 關鍵:static:: 獲取子類靜態屬性
$sql = "SELECT * FROM {$table} WHERE id = ?";
// ... 執行查詢並返回 static 實例
}
// 內部輔助:不希望被覆寫,用 self
private static function escape(string $val): string {
return addslashes($val);
}
public static function query(string $sql) {
self::escape($sql); // 內部實現細節,鎖定父類
}
}
class User extends Model {
protected static string $table = 'users';
}
class Order extends Model {
protected static string $table = 'orders';
}
$user = User::find(1); // 查 users 表
$order = Order::find(1); // 查 orders 表
class A {
public static function who() {
echo get_called_class() . "\n"; // 等同於 static::class
}
}
class B extends A {}
B::who(); // B
// 手動觸發延遲綁定
forward_static_call(['B', 'who']); // B
static:: 實現多態。self:: (或 private static)。self:: 能訪問子類屬性 —— 不能,編譯期已鎖定。static:: 有性能損耗 —— 微乎其微,PHP 7+ 高度優化。static:: 可用於屬性、方法、常量、new static() 實例化。