變量作用域決定變量的可見範圍與生命週期。PHP 的作用域規則獨特:只有函數建立新作用域,控制結構 (if/for/while) 不建立作用域,這與 C/Java 等語言截然不同。
<?php
if (true) {
$a = 'var a'; // 這裡的 $a 會「洩漏」到外部
}
var_dump($a); // string(5) "var a" - 可見!
for ($i = 0; $i < 1; $i++) {
$b = 'var b';
for ($j = 0; $j < 1; $j++) {
$c = 'var c';
}
var_dump($c); // 可見
}
var_dump($b); // 可見
var_dump($c); // 可見
?>
結論:if、for、while、foreach 的花括號 不構成 新作用域。
<?php
function test() {
$local = 'function scope';
}
test();
var_dump($local); // NULL - 函數外不可見
?>
<?php
$global = 'global value';
function outer() {
$global = 'outer local'; // 區域變量,遮蔽全域
function inner() {
global $global; // 宣告引用全域變量
var_dump($global); // string(12) "global value"
}
inner();
}
outer();
?>
關鍵點:global 無視嵌套層級,直接綁定腳本全域符號表中的變量。
<?php
$x = 10;
function test() {
$GLOBALS['x'] = 20; // 直接修改全域
}
test();
echo $x; // 20
?>
<?php
function counter() {
static $count = 0; // 僅初始化一次
$count++;
echo $count . "\n";
}
counter(); // 1
counter(); // 2
counter(); // 3
?>
<?php
$factor = 10;
// use 關鍵字顯式捕獲 (按值捕獲)
$multiply = function($x) use ($factor) {
return $x * $factor;
};
echo $multiply(5); // 50
// 按引用捕獲 (&)
$counter = function() use (&$factor) {
return ++$factor;
};
echo $counter(); // 11
echo $factor; // 11 (外部變量也被修改)
// PHP 7.4+ 箭頭函數:自動按值捕獲所有外部變量
$scale = fn($x) => $x * $factor; // 等同 use($factor)
?>
| 構造 | 是否創建新作用域 | 備註 |
|---|---|---|
| function | ✅ 是 | 區域作用域 |
| class 方法 | ✅ 是 | 同函數 |
| if / else | ❌ 否 | 變量外洩 |
| for / while / foreach | ❌ 否 | 變量外洩 |
| try / catch | ❌ 否 | 異常變量外洩 |
| 匿名函數 | ✅ 是 | 可捕獲外部 |
| 箭頭函數 | ✅ 是 | 自動捕獲 |
staticuse ($a, &$b) 區分值/引用declare(strict_types=1) 搭配類型聲明減少隱性錯誤理解 PHP 獨特的作用域規則,能避免「變量意外外洩」與「全域變量濫用」這兩大類常見 Bug,編寫出更可預測、可測試的代碼。