Skip to content

变量基础

变量是程序中用于存储数据的"容器"。PHP 中的变量以美元符号 $ 开头,具有弱类型特性,可以存储不同类型的数据。理解变量的基本概念是 PHP 编程的核心基础。

前置知识

基础概念

PHP 中的变量用一个美元符号 $ 后面跟变量名来表示。变量名区分大小写。PHP 是一种弱类型(动态类型)语言,变量不需要预先声明类型,赋值时自动确定类型。

变量的基本特征

  • $ 符号开头
  • 变量名区分大小写($name$Name 是不同变量)
  • 无需预先声明,赋值即创建
  • 可以在不同时候存储不同类型的值

变量命名规则

有效的变量名

变量名由字母(A-Za-z,以及字节值 128~255 的字符)或下划线 _ 开头,后面可以跟任意数量的字母、数字或下划线。正则表达式为:^[a-zA-Z_\x80-\xff][a-zA-Z0-9_\x80-\xff]*$

php
<?php
declare(strict_types=1);

// 有效的变量名
$name = "Alice";
$firstName = "Bob";
$_4site = "example.com";        // 以下划线开头
$i站点 = "mansikka";             // 包含多字节字符(UTF-8 编码有效)

echo $name . "\n";               // 输出: Alice
echo $firstName . "\n";          // 输出: Bob

// 变量名区分大小写
$var = "Bob";
$Var = "Joe";
echo "$var, $Var\n";             // 输出: Bob, Joe

无效的变量名

php
<?php
declare(strict_types=1);

// 错误:以数字开头
// $4site = "not yet";  // Parse error

// 错误:以特殊字符开头
// $@var = "test";      // Parse error

动态访问非标准变量名

PHP 接受任意字节序列作为变量名,不遵循上述命名规则的变量名可以通过花括号语法动态访问:

php
<?php
declare(strict_types=1);

// 使用花括号访问非标准变量名
${'invalid-name'} = "bar";
$name = "invalid-name";
echo ${'invalid-name'} . "\n";   // 输出: bar
echo $$name . "\n";               // 输出: bar(可变变量)

$this 是特殊变量

$this 是一个特殊变量,在对象方法中引用当前对象实例。PHP 7.1.0 之后,$this 不能被赋值(之前可以通过可变变量间接赋值)。

赋值方式

传值赋值(默认)

PHP 变量默认使用传值赋值。将一个变量的值赋给另一个变量时,会复制原始值。改变其中一个变量不会影响另一个:

php
<?php
declare(strict_types=1);

// 传值赋值
$a = "Hello";
$b = $a;        // $b 获得了 $a 的副本
$b = "World";   // 修改 $b 不影响 $a

echo $a . "\n"; // 输出: Hello
echo $b . "\n"; // 输出: World

对于对象类型,虽然变量本身是传值赋值(复制了对象的引用指针),但两者指向同一个对象实例。修改对象的属性会影响两个变量:

php
<?php
declare(strict_types=1);

class Config
{
    public string $name = "default";
}

$obj1 = new Config();
$obj2 = $obj1;          // 传值赋值,但都指向同一对象
$obj2->name = "custom";

echo $obj1->name . "\n"; // 输出: custom(受影响)
echo $obj2->name . "\n"; // 输出: custom

引用赋值

引用赋值使用 & 符号,使新变量成为原变量的别名。两者共享同一个值,修改其中一个会影响另一个:

php
<?php
declare(strict_types=1);

// 引用赋值
$foo = "Bob";
$bar = &$foo;           // $bar 是 $foo 的引用
$bar = "My name is {$bar}";

echo $bar . "\n";       // 输出: My name is Bob
echo $foo . "\n";       // 输出: My name is Bob(同样被修改)

引用赋值的限制

只有具名变量才能被引用赋值,不能对没有名字的表达式使用引用:

php
<?php
declare(strict_types=1);

$foo = 25;
$bar = &$foo;          // 合法:引用已命名变量

// $bar = &(24 * 7);   // 非法:不能引用无名字的表达式

function test(): int
{
    return 25;
}

// $bar = &test();      // 非法:函数没有通过引用返回

详细说明

类型推导

PHP 是弱类型语言,变量的类型由赋值的内容自动决定。可以使用 gettype() 函数查看变量类型:

php
<?php
declare(strict_types=1);

// PHP 自动推导变量类型
$intVar = 42;               // int
$floatVar = 3.14;           // float
$stringVar = "Hello";       // string
$boolVar = true;            // bool
$arrayVar = [1, 2, 3];      // array
$nullVar = null;             // null

echo gettype($intVar) . "\n";    // integer
echo gettype($floatVar) . "\n";  // double
echo gettype($stringVar) . "\n"; // string
echo gettype($boolVar) . "\n";   // boolean
echo gettype($arrayVar) . "\n";  // array
echo gettype($nullVar) . "\n";   // NULL

未初始化的变量

PHP 不强制声明变量,访问未初始化的变量会触发 E_WARNING(PHP 8.0.0 之前是 E_NOTICE),其默认值为 null。可以使用 isset() 检测变量是否已初始化:

php
<?php
declare(strict_types=1);

// 未初始化变量
// var_dump($undefinedVar); // Warning: Undefined variable

// 使用 isset() 安全检测
if (isset($undefinedVar)) {
    echo "Variable is set\n";
} else {
    echo "Variable is not set\n"; // 输出此行
}

// 使用 null 合并运算符(PHP 7.0+)提供默认值
$name = $undefinedVar ?? "default";
echo $name . "\n"; // 输出: default

自动数组生成

将元素追加到未定义的变量时,PHP 会自动创建一个数组:

php
<?php
declare(strict_types=1);

// 自动创建数组
$unsetArray[] = "value";  // 不会产生警告
$unsetArray[] = "another";

print_r($unsetArray);
// 输出: Array ( [0] => value [1] => another )

警告

依赖未初始化变量的默认行为是有风险的,尤其是在使用 include 包含文件时。始终显式初始化变量。

销毁变量

使用 unset() 语言结构可以销毁变量:

php
<?php
declare(strict_types=1);

$name = "Alice";
echo isset($name) ? "set" : "not set"; // 输出: set

unset($name);
echo isset($name) ? "set" : "not set"; // 输出: not set

// 销毁引用
$a = "value";
$b = &$a;
unset($b);          // 只解除 $b 的引用,不影响 $a
echo $a . "\n";    // 输出: value

实战示例

类型检测函数

php
<?php
declare(strict_types=1);

function analyzeVariable(mixed $value): string
{
    $type = gettype($value);
    $result = "Type: {$type}";

    if (is_int($value)) {
        $result .= " | Integer: {$value}";
    } elseif (is_float($value)) {
        $result .= " | Float: {$value}";
    } elseif (is_string($value)) {
        $result .= " | String length: " . strlen($value);
    } elseif (is_bool($value)) {
        $result .= " | Boolean: " . ($value ? "true" : "false");
    } elseif (is_null($value)) {
        $result .= " | Null value";
    } elseif (is_array($value)) {
        $result .= " | Array count: " . count($value);
    }

    return $result;
}

echo analyzeVariable(42) . "\n";
echo analyzeVariable(3.14) . "\n";
echo analyzeVariable("Hello World") . "\n";
echo analyzeVariable(true) . "\n";
echo analyzeVariable([1, 2, 3]) . "\n";

安全的变量初始化模式

php
<?php
declare(strict_types=1);

/**
 * 安全地获取配置值
 *
 * 使用嵌套的 null 合并运算符(PHP 7.0+)安全访问深层配置
 */
function getConfig(string $key, mixed $default = null): mixed
{
    static $config = null;

    if ($config === null) {
        $config = [
            "database" => [
                "host" => "localhost",
                "port" => 3306,
                "name" => "myapp",
            ],
            "cache" => [
                "enabled" => true,
                "ttl" => 3600,
            ],
        ];
    }

    // 安全的多层访问
    return match ($key) {
        "db.host" => $config["database"]["host"] ?? $default,
        "db.port" => $config["database"]["port"] ?? $default,
        "db.name" => $config["database"]["name"] ?? $default,
        "cache.enabled" => $config["cache"]["enabled"] ?? $default,
        "cache.ttl" => $config["cache"]["ttl"] ?? $default,
        default => $default,
    };
}

echo getConfig("db.host") . "\n";        // localhost
echo getConfig("db.port") . "\n";        // 3306
echo getConfig("unknown", "N/A") . "\n"; // N/A

引用与传值的实际应用

php
<?php
declare(strict_types=1);

// 引用在修改函数参数时的用途
function addPrefix(string &$str, string $prefix): void
{
    $str = $prefix . $str;
}

$title = "World";
addPrefix($title, "Hello, ");
echo $title . "\n"; // 输出: Hello, World

// 多个变量交换(通过引用)
$a = "first";
$b = "second";

function swap(string &$x, string &$y): void
{
    $temp = $x;
    $x = $y;
    $y = $temp;
}

swap($a, $b);
echo "a={$a}, b={$b}\n"; // a=second, b=first

注意事项

1. 变量与常量的区别

常量和变量在不同的命名空间中。true$TRUE 是完全不同的:

php
<?php
declare(strict_types=1);

define("MY_CONST", 100);
$myConst = 200;

echo MY_CONST . "\n";  // 100(常量)
echo $myConst . "\n";  // 200(变量)

2. 不要依赖未初始化变量

php
<?php
declare(strict_types=1);

// 危险:依赖未初始化变量
function unsafeIncrement(): int
{
    // $count 未初始化,PHP 8 会产生 E_WARNING
    // return ++$count;
    // 安全的做法:
    static $count = 0;
    return ++$count;
}

3. 避免变量名与超级全局变量冲突

虽然不禁止,但避免创建与 $_GET$_POST$_SERVER 等同名的变量:

php
<?php
declare(strict_types=1);

// 不推荐:可能与内置变量混淆
// $_GET = "custom";

// 推荐:使用有意义的、不会冲突的名称
$getParams = $_GET;

最佳实践

  1. 始终初始化变量:在使用前显式赋初值,避免依赖默认行为
  2. 使用有意义的变量名$userAge$a 更好理解
  3. 遵循驼峰命名:按照 PSR-12,变量使用 $camelCase 风格
  4. 使用 isset()??:安全访问可能未定义的变量
  5. 谨慎使用引用:引用会降低代码可读性,仅在必要时使用
  6. 使用 declare(strict_types=1):在严格模式下编写更安全的代码
  7. 利用类型声明:PHP 7.0+ 支持函数参数和返回值类型声明

下一节

理解了变量的基本概念后,接下来将深入学习变量的作用域规则——全局变量、局部变量、静态变量以及超级全局变量。请阅读 变量作用域

参考链接