全域性變數最佳實踐
我們可以用下面的虛擬碼來說明這個問題
function `foo()` {
global $bob;
$bob->doSomething();
}
你的第一個問題很明顯
$bob
來自哪裡?
你困惑嗎?好。你剛剛瞭解了為什麼全域性變數令人困惑並被認為是一種不好的做法。
如果這是一個真正的程式,你的下一個樂趣是追蹤 $bob
的所有例項,並希望你找到合適的一個(如果 $bob
到處使用,這會變得更糟)。更糟糕的是,如果其他人去定義 $bob
(或者你忘記並重用了那個變數)你的程式碼可能會破壞(在上面的程式碼示例中,擁有錯誤的物件,或根本沒有物件,會導致致命的錯誤)。
由於幾乎所有 PHP 程式都使用像 include('file.php');
這樣的程式碼,因此維護這樣的程式碼會使你新增的檔案越多,指數越大。
此外,這使得測試應用程式的任務非常困難。假設你使用全域性變數來儲存資料庫連線:
$dbConnector = new DBConnector(...);
function doSomething() {
global $dbConnector;
$dbConnector->execute("...");
}
為了對這個函式進行單元測試,你必須覆蓋全域性 $dbConnector
變數,執行測試然後將其重置為原始值,這很容易出錯:
/**
* @test
*/
function testSomething() {
global $dbConnector;
$bkp = $dbConnector; // Make backup
$dbConnector = Mock::create('DBConnector'); // Override
assertTrue(foo());
$dbConnector = $bkp; // Restore
}
我們如何避免全域性?
避免全域性變數的最佳方法是稱為 依賴注入 的哲學。這是我們將所需工具傳遞給函式或類的地方。
function foo(\Bar $bob) {
$bob->doSomething();
}
這更容易理解和維護。沒有猜測 $bob
的設定,因為呼叫者有責任知道(它傳遞給我們我們需要知道的東西)。更好的是,我們可以使用型別宣告來限制傳遞的內容。
所以我們知道 $bob
要麼是 Bar
類的一個例項,要麼是 Bar
的一個例項,這意味著我們知道我們可以使用該類的方法。結合標準自動載入器(自 PHP 5.3 開始提供),我們現在可以跟蹤定義 Bar
的位置。PHP 7.0 或更高版本包括擴充套件型別宣告,你還可以使用標量型別(如 int
或 string
)。
Version = 4.1
超全域性變數
PHP 中的超級全域性變數是預定義變數,它們始終可用,可以從整個指令碼的任何範圍訪問。
沒有必要做全域性$變數; 在函式/方法,類或檔案中訪問它們。
這些 PHP 超全域性變數如下所示: