PHP 零基础教程

PHP 变量作用域

PHP 变量拥有作用域 (Scope),这决定了在脚本的哪些地方可以访问或修改它们。每个变量都存在于一个特定的上下文中,除非明确声明,否则它的可用性将被严格限制在该上下文中。

1. 局部作用域 (Local Scope)

在函数内部声明的变量拥有局部作用域。这意味着它们只能从该特定函数的内部被访问。一旦函数执行完毕,这些局部变量就会被销毁。

拥有局部作用域的变量无法从声明它的函数外部被访问。如果你尝试从全局作用域访问局部变量,将会导致一个“未定义变量 (undefined variable)”的错误。

<?php
function greetUser() {
    $message = "来自函数内部的问候!"; // $message 拥有局部作用域
    echo $message;
}

greetUser(); // 调用函数,$message 被创建并使用

// 尝试在函数外部访问 $message 会导致错误
// echo $message; // 这行代码会引发一个 "Undefined variable: message" 错误
?>

在上面的例子中,$message 是在 greetUser() 内部创建的,并且仅在该函数执行期间存在。不同的函数可以声明同名的变量而不会发生冲突,因为它们的作用域是完全隔离的。

<?php
function calculateSum($a, $b) {
    $result = $a + $b; // $result 拥有局部作用域
    return $result;
}

function displayGreeting($name) {
    $greeting = "欢迎," . $name . "!"; // $greeting 拥有局部作用域
    echo $greeting . "\n";
}

$sum = calculateSum(5, 10);
echo "总和是:" . $sum . "\n";
displayGreeting("爱丽丝");

// 尝试在这里访问 $result 或 $greeting 将会失败
// echo $result; // 错误
// echo $greeting; // 错误
?>

calculateSum 中的参数 $a$b 也是局部变量,充当传递给函数的实际值的占位符。

2. 全局作用域 (Global Scope)

任何函数外部声明的变量拥有全局作用域。默认情况下,这些变量可以从脚本的任何地方被访问,唯独不能在函数内部直接访问

要在函数内部访问全局变量,你必须使用 global 关键字显式声明它,或者通过 $GLOBALS 超全局数组来访问它。

2.1 使用 global 关键字

global 关键字向 PHP 明确指示:函数内部的这个变量应该引用全局版本的那个变量,而不是去创建一个新的局部变量。

<?php
$appName = "我的 PHP 应用"; // $appName 拥有全局作用域
$version = "1.0";           // $version 拥有全局作用域

function displayAppInfo() {
    global $appName; // 声明此函数内的 $appName 引用的是全局的 $appName
    global $version; // 声明此函数内的 $version 引用的是全局的 $version
    
    echo "应用名称:" . $appName . "\n";
    echo "版本:" . $version . "\n";
}

displayAppInfo(); 
// 输出:应用名称:我的 PHP 应用,版本:1.0

function updateVersion() {
    global $version;
    $version = "1.1"; // 修改了全局的 $version 变量
    echo "函数内部更新后的版本:" . $version . "\n";
}

updateVersion(); 
// 输出:函数内部更新后的版本:1.1

echo "当前的全局版本:" . $version . "\n"; 
// 输出:当前的全局版本:1.1 (外部的变量确实被改变了)
?>

使用 global 允许在函数内部对全局变量进行读取和写入操作。

2.2 使用 $GLOBALS 超全局数组

PHP 提供了一个名为 $GLOBALS 的特殊超全局数组。这个关联数组包含了在全局作用域中可用的所有变量的引用。变量名就是该数组的键 (Key)。

这种方法通常比 global 关键字更受青睐,因为它代码意图更清晰,并且能避免潜在的命名冲突。

<?php
$pageTitle = "产品列表"; // 全局变量
$itemsPerPage = 10;      // 全局变量

function generateHeader() {
    // 使用 $GLOBALS 数组访问全局变量
    echo "<h1>" . $GLOBALS['pageTitle'] . "</h1>\n";
    echo "<p>每页显示 " . $GLOBALS['itemsPerPage'] . " 个项目。</p>\n";
}

function updateItemsPerPage($newCount) {
    // 使用 $GLOBALS 数组修改全局变量
    $GLOBALS['itemsPerPage'] = $newCount;
    echo "每页项目数已更新为:" . $GLOBALS['itemsPerPage'] . "\n";
}

generateHeader();
// 输出:
// <h1>产品列表</h1>
// <p>每页显示 10 个项目。</p>

updateItemsPerPage(20); // 全局修改了 $itemsPerPage
echo "更新后的全局 itemsPerPage:" . $itemsPerPage . "\n"; 
// 输出:更新后的全局 itemsPerPage:20
?>

global $variable;$GLOBALS['variable'] 都能达到在函数内部访问全局变量的目的。$GLOBALS 数组更加灵活,因为它允许使用字符串键动态地访问全局变量。

3. 静态作用域 (Static Scope)

static(静态)关键字应用于函数内部的局部变量。与函数执行完毕即被销毁的普通局部变量不同,静态变量在同一个函数的多次调用之间会保留它们最后的值。

它们只在脚本执行期间被初始化一次(也就是函数第一次被调用时)。

<?php
function trackVisits() {
    static $counter = 0; // $counter 是一个静态变量
    $counter++;
    echo "页面访问量:" . $counter . "\n";
}

trackVisits(); // 输出:页面访问量:1
trackVisits(); // 输出:页面访问量:2
trackVisits(); // 输出:页面访问量:3

// 静态变量 $counter 在函数外部是无法访问的
// echo $counter; // 这会导致 "Undefined variable: counter" 错误
?>

trackVisits() 的例子中,$counter 只被初始化为 0 一次。在随后的调用中,它记住了自己之前的值(1,然后是 2),并在此基础上递增。如果 $counter 只是一个普通的局部变量,它在每次函数调用时都会被重新初始化为 0,那么输出将永远是“页面访问量:1”。

静态变量非常适合用于在函数内部维护状态,而无需诉诸于全局变量或在函数内外来回传递值。

<?php
function generateUniqueId() {
    static $lastId = 1000; // 初始化一个基础 ID
    $lastId++;
    return "USER_" . $lastId;
}

echo generateUniqueId() . "\n"; // 输出:USER_1001
echo generateUniqueId() . "\n"; // 输出:USER_1002
echo generateUniqueId() . "\n"; // 输出:USER_1003
?>

在这里,generateUniqueId() 使用了静态变量 $lastId 来确保每个生成的 ID 都是唯一且递增的。