在物件導向開發中,並非所有類別都需要實例化多個對象。工具類、配置管理、單例服務等場景,使用 static 關鍵字定義靜態屬性與方法,可避免 new 開銷、簡化調用語法、實現跨請求的狀態共享。本文系統梳理 PHP static 的語法規則、內部調用、繼承行為與實戰模式。
<?php
class HelloWorld {
public static function say() {
return 'Hello World!';
}
}
// 直接透過類名調用,無需實例化
echo HelloWorld::say(); // 輸出:Hello World!
?>
雖然未加 static 的實例方法在 PHP 也能靜態調用(HelloWorld::say()),但會觸發 E_DEPRECATED 警告且語意不清,**強烈建議明確加上 static**。
<?php
class Foo {
private static function internal() {
return 'internal';
}
public static function publicApi() {
// 同類靜態方法調用
echo self::internal(); // 輸出:internal
}
}
Foo::publicApi();
?>
self:::綁定**定義該方法的類別**(早期靜態綁定)static:::綁定**實際調用的類別**(晚期靜態綁定,LSB),PHP 5.3+ 支援<?php
class Counter {
public static $count = 0;
public static function increment() {
self::$count++;
}
}
Counter::increment();
Counter::increment();
echo Counter::$count; // 輸出:2
?>
靜態屬性屬於**類別本身**,不屬於某個實例。所有實例、靜態調用共享同一份記憶體空間,生命週期貫穿整個腳本執行期。
<?php
class ParentClass {
public static function who() { echo 'Parent'; }
}
class ChildClass extends ParentClass {
public static function who() { echo 'Child'; }
}
ChildClass::who(); // 輸出:Child
?>
<?php
class ParentClass {
public static function greet() { return 'Hello from Parent'; }
}
class ChildClass extends ParentClass {
public static function greet() {
// 錯誤:self::greet() 會調用 ChildClass::greet() 導致無限遞歸
// 正確:
return parent::greet() . ' -> Child';
}
}
echo ChildClass::greet(); // 輸出:Hello from Parent -> Child
?>
<?php
class Base {
public static $val = 'base';
}
class DerivedA extends Base {}
class DerivedB extends Base {}
DerivedA::$val = 'A';
DerivedB::$val = 'B';
echo Base::$val; // base
echo DerivedA::$val; // A
echo DerivedB::$val; // B
?>
**關鍵點**:子類**首次**對靜態屬性賦值時,會在子類作用域建立獨立副本,不再影響父類與其他兄弟類。這與 Java/C# 行為一致。
<?php
class OrderStatus {
public const PENDING = 0;
public const PAID = 1;
public const SHIPPED = 2;
public const COMPLETED = 3;
public const CANCELLED = -1;
// 靜態方法封裝業務邏輯
public static function canCancel(int $status): bool {
return in_array($status, [self::PENDING, self::PAID], true);
}
}
// 使用
$status = OrderStatus::PAID;
if (OrderStatus::canCancel($status)) {
// 允許取消
}
?>
PHP 8.1+ 推薦改用 enum 實現更強類型的狀態機,但 static const 組合在舊版本仍是最佳實踐。
<?php
class Model {
protected static $table = 'base_table';
public static function getTable(): string {
return static::$table; // LSB:取調用類的 $table
}
}
class User extends Model {
protected static $table = 'users';
}
class Post extends Model {
protected static $table = 'posts';
}
echo User::getTable(); // users
echo Post::getTable(); // posts
?>
若改用 self::$table,所有子類都會回傳 base_table。LSB 是 ActiveRecord、Repository 等基礎框架類的核心機制。
$this 綁定)| 場景 | 推薦寫法 |
|---|---|
| 工具函數、純邏輯運算 | public static function |
| 類級別配置、快取、計數器 | public static $property |
| 基礎類定義預設值,子類覆寫 | protected static $prop + static::$prop (LSB) |
| 子類調用父類靜態方法 | parent::method() |
| 常數分組 | public const (PHP 7.1+) 或 public static |
善用 static 能讓代碼更簡潔、效能更高,但需謹記「靜態即全域」的副作用,避免濫用導致耦合度過高、測試困難。