ZetCode

PHP 变量作用域

上次修改时间:2025 年 5 月 18 日

欢迎来到关于 PHP 变量作用域的教程!理解变量在程序中如何以及在哪里被访问对于编写高效且无错误的代码至关重要。

作用域指的是定义变量的上下文,并决定了它在程序不同部分的可访问性。根据变量的声明位置,它可能只在特定函数内可用,在整个脚本中可用,或者在函数调用之间保留其值。

PHP 提供了几种类型的变量作用域,包括局部、全局、静态和函数参数。掌握这些作用域将帮助您有效地组织代码,避免意外行为,并提高可维护性。

局部作用域

在函数内声明的变量具有局部作用域,并且只能在该函数内部访问。这种隔离可以防止命名冲突并使函数自包含。

local_scope.php
<?php

declare(strict_types=1);

function calculateTotal() {
    $price = 100; // Local variable
    $tax = $price * 0.08;
    return $price + $tax;
}

echo "Total: " . calculateTotal() . "\n";

// This would cause an error - $price not accessible here
// echo "Price: $price\n";

function testScope() {
    $price = 200; // Different local variable
    echo "Inside function: $price\n";
}

testScope();

这演示了局部变量作用域。每个 $price 变量仅存在于其函数内。试图在函数外部访问它们将导致未定义变量错误。

λ php local_scope.php
Total: 108
Inside function: 200

全局作用域

在函数外部声明的变量具有全局作用域。要在函数内部访问全局变量,您必须使用 global 关键字或 $GLOBALS 数组。

global_scope.php
<?php

declare(strict_types=1);

$globalVar = "I'm global"; // Global variable

function testGlobal() {
    global $globalVar; // Access global variable
    echo "Inside function (global keyword): $globalVar\n";
    
    echo "Inside function (GLOBALS array): " . 
         $GLOBALS['globalVar'] . "\n";
    
    $globalVar = "Modified inside function";
}

testGlobal();
echo "After modification: $globalVar\n";

// Another global variable
$counter = 0;

function incrementCounter() {
    global $counter;
    $counter++;
}

incrementCounter();
incrementCounter();
echo "Counter: $counter\n";

这展示了如何在函数内部访问和修改全局变量。对函数内部的全局变量所做的更改会在函数调用后保留。global 关键字和 $GLOBALS 数组提供等效的访问方式。

λ php global_scope.php
Inside function (global keyword): I'm global
Inside function (GLOBALS array): I'm global
After modification: Modified inside function
Counter: 2

静态变量

静态变量在函数调用之间保留其值,同时保持函数局部性。它们仅在首次遇到时初始化一次。

static_variables.php
<?php

declare(strict_types=1);

function counter() {
    static $count = 0; // Static variable
    $count++;
    echo "Count: $count\n";
}

counter(); // Count: 1
counter(); // Count: 2
counter(); // Count: 3

function rememberValues() {
    static $values = [];
    $values[] = rand(1, 100);
    echo "Values: " . implode(', ', $values) . "\n";
}

rememberValues();
rememberValues();
rememberValues();

这演示了静态变量保留其在函数调用之间的值。与常规局部变量不同,静态变量不会在每次函数调用时重新初始化,这使得它们对于计数器和缓存非常有用。

λ php static_variables.php
Count: 1
Count: 2
Count: 3
Values: 42
Values: 42, 17
Values: 42, 17, 89

函数参数

函数参数在函数内部具有局部作用域。默认情况下,参数按值传递,但它们可以使用 & 按引用传递。

function_parameters.php
<?php

declare(strict_types=1);

function square($num) { // Pass by value
    $num *= $num;
    return $num;
}

$value = 5;
echo "Square: " . square($value) . "\n";
echo "Original value: $value\n"; // Unchanged

function addPrefix(&$str) { // Pass by reference
    $str = "Mr. " . $str;
}

$name = "Smith";
addPrefix($name);
echo "Modified name: $name\n"; // Changed

function setDefault($param = 10) { // Default value
    echo "Parameter: $param\n";
}

setDefault(42);
setDefault();

这展示了函数参数的作用域和行为。按值传递的参数创建副本,而按引用传递的参数修改原始值。当未提供参数时,使用默认值。

λ php function_parameters.php
Square: 25
Original value: 5
Modified name: Mr. Smith
Parameter: 42
Parameter: 10

包含文件中的变量作用域

在主脚本中声明的变量在包含的文件中可用,而在包含文件中声明的变量取决于它们的包含位置。

config.php.php
<?php

declare(strict_types=1);

$dbHost = 'localhost';
$dbUser = 'admin';

这是 config.php 文件。它包含数据库配置变量,这些变量可以包含在其他脚本中。

main.php
<?php

declare(strict_types=1);

$mainVar = "From main script";

include 'config.php';

function testIncludedVars() {
    global $dbHost;
    echo "DB Host inside function: $dbHost\n";
}

echo "DB User: $dbUser\n";
testIncludedVars();
echo "Main var: $mainVar\n";

这演示了包含文件的变量作用域。来自主脚本和包含文件的变量共享全局作用域,除非在函数内部声明。适当的组织可以防止命名冲突。

λ php included_vars.php
DB User: admin
DB Host inside function: localhost
Main var: From main script

闭包和 'use' 关键字

匿名函数(闭包)可以使用 use 关键字从父作用域继承变量。这会创建一个“封闭”指定变量的闭包。

closures.php
<?php

declare(strict_types=1);

$factor = 10;

// Closure with 'use' keyword
$multiplier = function($n) use ($factor) {
    return $n * $factor;
};

echo "Multiplier: " . $multiplier(5) . "\n";

// Variables are bound by value unless specified by reference
$counter = 0;
$increment = function() use (&$counter) {
    $counter++;
};

$increment();
$increment();
echo "Counter: $counter\n";

// Using multiple variables
$prefix = "User";
$suffix = "Active";
$format = function($name) use ($prefix, $suffix) {
    return "$prefix: $name ($suffix)";
};

echo $format("Alice") . "\n";

这展示了闭包如何从父作用域捕获变量。默认情况下,变量按值传递。& 修饰符允许按引用传递以修改原始变量。

λ php closures.php
Multiplier: 50
Counter: 2
User: Alice (Active)

超全局变量

PHP 提供了特殊的超全局变量,可以从任何作用域访问,而无需使用 global 关键字。这些变量包含服务器、请求和环境信息。

superglobals.php
<?php

declare(strict_types=1);

// Accessing superglobals
echo "Your IP: {$_SERVER['REMOTE_ADDR']}\n";
echo "PHP Version: {$_SERVER['PHP_VERSION']}\n";

// Working with $_GET parameters
// Assume URL: script.php?name=Alice&age=30
echo "Name: {$_GET['name']}\n";
echo "Age: {$_GET['age']}\n";

// Session example
session_start();
$_SESSION['visits'] = ($_SESSION['visits'] ?? 0) + 1;
echo "Session visits: {$_SESSION['visits']}\n";

// Cookie example
$cookieName = 'test_cookie';
$_COOKIE[$cookieName] = 'cookie_value';
echo "Cookie: {$_COOKIE[$cookieName']}\n";

这演示了常见的超全局变量。这些特殊的数组始终可用,并提供对请求数据、服务器信息、会话、cookie 等的访问。

λ php superglobals.php
Your IP: 127.0.0.1
PHP Version: 8.2.5
Name: Alice
Age: 30
Session visits: 1
Cookie: cookie_value

最佳实践

适当的变量作用域管理可以提高代码质量并防止错误。请遵循这些准则以有效使用作用域。

best_practices.php
<?php

declare(strict_types=1);

// 1. Minimize global variables
$config = []; // Limited globals for configuration

// 2. Use function parameters and return values instead of globals
function calculateArea($width, $height) {
    return $width * $height;
}

// 3. Use static variables for function persistence
function getUniqueId() {
    static $id = 0;
    return ++$id;
}

// 4. Be explicit with variable scope
function processUser($user) {
    global $config; // Explicit global declaration
    
    if (empty($user)) {
        return false;
    }
    
    static $cache = []; // Static cache
    
    if (isset($cache[$user['id']])) {
        return $cache[$user['id']];
    }
    
    // Process user...
    $cache[$user['id']] = $user;
    return $user;
}

// 5. Use closures effectively
$logger = function($message) use ($config) {
    $prefix = $config['log_prefix'] ?? '';
    echo "[$prefix] $message\n";
};

// 6. Avoid modifying superglobals directly
$cleanGet = filter_input_array(INPUT_GET, FILTER_SANITIZE_STRING);

// 7. Use dependency injection instead of globals
class UserService {
    private $db;
    
    public function __construct($db) {
        $this->db = $db;
    }
    
    public function getUser($id) {
        // Use $this->db instead of global $db
    }
}

这些最佳实践有助于有效地管理变量作用域。最小化全局变量、使用适当的封装以及明确说明作用域可以使代码更易于维护且不易出错。

理解 PHP 变量作用域是编写健壮应用程序的基础。局部作用域提供隔离,全局作用域在需要时实现共享访问,静态变量提供持久性。适当的作用域管理可以防止命名冲突,并使代码更可预测和可维护。

作者

我的名字是 Jan Bodnar,我是一位充满激情的程序员,拥有丰富的编程经验。自 2007 年以来,我一直在撰写编程文章。到目前为止,我撰写了超过 1,400 篇文章和 8 本电子书。我拥有超过十年的编程教学经验。

列出 所有 PHP 教程