首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 綜合知識

PHP 變量作用域全解析:全局、靜態、超全局與引用陷阱

     編輯:PHP 綜合知識

核心概念:三種作用域

PHP 變量作用域分為:全局作用域(腳本主流程)、局部/函數作用域(函數內部)、超全局作用域($GLOBALS、$_GET 等)。

全局變量在函數中:必須聲明

與 C/C++ 不同,PHP 函數預設不訪問全局變量:

<?php
$a = 1;
function test() {
    echo $a; // 無輸出,訪問的是未初始化的局部變量 $a
}
test();
?>

兩種訪問全局變量的方式

<?php
$a = 1; $b = 2;

// 方式 1:global 關鍵字(引用綁定)
function sum_global() {
    global $a, $b;
    $b = $a + $b; // 修改全局 $b
}

// 方式 2:$GLOBALS 超全局數組(直接訪問)
function sum_globals() {
    $GLOBALS['b'] = $GLOBALS['a'] + $GLOBALS['b'];
}
?>

靜態變量:跨調用保持狀態

static 變量僅在函數局部可見,但生命週期贯穿整個腳本執行:

<?php
function counter() {
    static $count = 0; // 僅初始化一次
    echo $count++;
}
counter(); // 0
counter(); // 1
counter(); // 2
?>

遞歸中的靜態變量

<?php
function recurse($limit = 10) {
    static $depth = 0;
    $depth++;
    echo "Depth: $depth\n";
    if ($depth < $limit) recurse($limit);
    $depth--; // 回溯恢復
}
recurse(3);
?>

超全局變量:無處不在

PHP 4.1.0+ 引入 9 個超全局變量,所有作用域自動可見,無需 global:

  • $GLOBALS — 所有全局變量的引用
  • $_SERVER — 服務器/執行環境信息
  • $_GET / $_POST — HTTP 參數
  • $_COOKIE — Cookie 數據
  • $_SESSION — Session 數據
  • $_FILES — 上傳文件信息
  • $_ENV — 環境變量
  • $_REQUEST — 合併 GET/POST/COOKIE(受 variables_order 影響)

引用陷阱:global 與 static 的引用行為

Zend Engine 1 (PHP 4) 以引用實現 global/static,導致意外行為:

<?php
function test_ref() {
    global $obj;
    $obj = &new StdClass; // 引用賦值
}
function test_noref() {
    global $obj;
    $obj = new StdClass; // 值賦值
}
test_ref();
var_dump($obj); // NULL (!)
test_noref();
var_dump($obj); // object(StdClass)#1 (0) {}
?>

原因:global $obj 建立到全局符號表的引用,$obj = &new 修改了引用指向而非對象本身。

static 引用同理

<?php
function &get_ref() {
    static $obj;
    if (!isset($obj)) $obj = &new StdClass;
    $obj->prop++;
    return $obj;
}
function &get_noref() {
    static $obj;
    if (!isset($obj)) $obj = new StdClass;
    $obj->prop++;
    return $obj;
}
$a = get_ref(); $b = get_ref(); // $a, $b 指向同一對象,prop=2
$c = get_noref(); $d = get_noref(); // $c, $d 指向同一對象,prop=2
// 但若修改靜態變量本身的引用關係,行為不同
?>

靜態變量初始化限制

靜態變量聲明時只能使用字面量常量,不能使用表達式:

<?php
function foo() {
    static $a = 0;       // ✅ 正確
    static $b = 1 + 2;   // ❌ Parse error
    static $c = sqrt(4); // ❌ Parse error
}
?>

最佳實踐總結

場景推薦方式避坑提醒
函數內讀寫全局配置$GLOBALS['config']避免 global 產生隱式引用副作用
函數內計數/緩存static $var = 初始值初始值必須是字面量
跨文件共享狀態類靜態屬性 / 單例模式優於全局變量,可控性更強
引用對象賦值$obj = new Class()PHP 5+ 對象默認引用傳遞,無需 &

現代 PHP 替代方案

PHP 7.1+ 建議使用 依賴注入容器、單例服務類、靜態類屬性 替代全局/靜態變量,實現可測試、可維護的架構:

<?php
// 推薦:服務類封裝狀態
class Config {
    private static $instance;
    private $data = [];
    private function __construct() {}
    public static function getInstance() {
        return self::$instance ??= new self();
    }
    public function get($key) { return $this->data[$key] ?? null; }
    public function set($key, $val) { $this->data[$key] = $val; }
}
// 使用
Config::getInstance()->set('debug', true);
?>
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved