static 關鍵字在 PHP 中有兩種截然不同的語境:函數內局部靜態變量、類中靜態屬性/方法。本文聚焦函數級局部靜態變量,對比全局變量,揭示其獨特生命週期與使用陷阱。
function counter() {
static $count = 0; // 僅初始化一次
$count++;
echo $count . "\n";
}
counter(); // 1
counter(); // 2
counter(); // 3
// $count 在函數調用間保持值,但作用域僅限函數內
| 特性 | 說明 | 代碼驗證 |
|---|---|---|
| 跨調用保持值 | 函數退出不銷毀,下次調用繼續使用 | 上例輸出 1,2,3 |
| 僅初始化一次 | 首次執行到聲明行時初始化,後續跳過 | static $v = rand(); 只隨機一次 |
| 初始化限制 | 只能用字面量/常量,不能用表達式/函數調用 | static $v = 1+1; ❌ 報錯 |
| 作用域局限 | 外部無法直接訪問,避免全局污染 | echo $count; ❌ Undefined |
// 遞歸深度計數
function traverse($node, $depth = 0) {
static $maxDepth = 0;
if ($depth > $maxDepth) $maxDepth = $depth;
// ... 遍歷子節點 ...
return $maxDepth;
}
// 惰性單例資源(如數據庫連接)
function getDb() {
static $pdo = null;
if ($pdo === null) {
$pdo = new PDO($dsn, $user, $pass);
}
return $pdo;
}
$globalCounter = 0; // 全局變量本質上就是靜態存儲
function globalCounter() {
global $globalCounter;
$globalCounter++;
echo $globalCounter . "\n";
}
globalCounter(); // 1
globalCounter(); // 2
globalCounter(); // 3
echo $globalCounter; // 3 - 外部可直接訪問修改
| 維度 | 局部靜態 static $v | 全局變量 global $v |
|---|---|---|
| 作用域 | 僅所在函數 | 全腳本(需 global 聲明) |
| 初始化語法 | 聲明處賦值(限常量) | 任意位置賦值 |
| 封裝性 | 高,外部不可直接訪問 | 低,任何處可修改 |
| 命名衝突 | 無,函數級隔離 | 高風險,需規範前綴 |
| 適用場景 | 函數內部狀態保持 | 跨函數/文件共享狀態 |
class Foo {
public static $count = 0; // 類屬性,屬於類而非實例
public function inc() { self::$count++; }
}
$obj1 = new Foo(); $obj1->inc();
$obj2 = new Foo(); $obj2->inc();
echo Foo::$count; // 2 - 所有實例共享
// 晚靜態綁定 (PHP 5.3+)
class Bar extends Foo {
public static $count = 0;
}
Bar::$count = 5;
echo Foo::$count; // 2 (未改變)
echo Bar::$count; // 5 (獨立)
SplThreadLocal 或上下文管理器static $v = &$external; 會導致不可預期行為,避免引用賦值ReflectionClass::getStaticPropertyValue() 或重構為可注入依賴$fn = function() use (&$v) {})理解 static 變量的生命週期邊界,善用其封裝性避免全局污染,是編寫健壯 PHP 代碼的重要內功。