On this page

PHP 变量

基础

PHP 中的变量用一个美元符号后面跟变量名来表示。变量名是区分大小写的。
变量名与 PHP
中其它的标签一样遵循相同的规则。一个有效的变量名由字母或者下划线开头,后面跟上任意数量的字母,数字,或者下划线。
按照正常的正则表达式,它将被表述为:'`^[a-zA-Z_\x80-\xff][a-zA-Z0-9_\x80-\xff]*$`'。

>注意:

 在此所说的字母是 a-z,A-Z,以及 ASCII 字符从 128 到 255(`0x80-0xff`)。

>注意:

$this 是一个特殊的变量,它不能被赋值。

 PHP 7.1.0 之前,间接赋值(例如通过使用[可变变量](https://www.php.net/manual/zh/language.variables.variable.php))是可能的。

小技巧请参见用户空间命名指南

有关变量的函数信息见[变量函数](https://www.php.net/manual/zh/ref.var.php)。

<?php
$var = 'Bob';
$Var = 'Joe';
echo "$var, $Var";      // 输出 "Bob, Joe"

$4site = 'not yet';     // 非法变量名;以数字开头
$_4site = 'not yet';    // 合法变量名;以下划线开头
$i站点is = 'mansikka';  // 合法变量名;可以用中文
?>
变量默认总是传值赋值。那也就是说,当将一个表达式的值赋予一个变量时,整个原始表达式的值被赋值到目标变量。这意味着,例如,当一个变量的值赋予另外一个变量时,改变其中一个变量的值,将不会影响到另外一个变量。有关这种类型的赋值操作,请参阅[表达式](https://www.php.net/manual/zh/language.expressions.php)一章。
PHP 也提供了另外一种方式给变量赋值:[引用赋值](https://www.php.net/manual/zh/language.references.php)。这意味着新的变量简单的引用(换言之,“成为其别名” 或者 “指向”)了原始变量。改动新的变量将影响到原始变量,反之亦然。
使用引用赋值,简单地将一个 &
符号加到将要赋值的变量前(源变量)。例如,下列代码片断将输出“My name is Bob”两次:


<?php
$foo = 'Bob';              // 将 'Bob' 赋给 $foo
$bar = &$foo;              // 通过 $bar 引用 $foo
$bar = "My name is $bar";  // 修改 $bar 变量
echo $bar;
echo $foo;                 // $foo 的值也被修改
?>
有一点重要事项必须指出,那就是只有有名字的变量才可以引用赋值。


<?php
$foo = 25;
$bar = &$foo;      // 合法的赋值
$bar = &(24 * 7);  // 非法; 引用没有名字的表达式

function test()
{
   return 25;
}

$bar = &test();    // 非法
?>
虽然在 PHP 中并不需要初始化变量,但对变量进行初始化是个好习惯。未初始化的变量具有其类型的默认值 - 布尔类型的变量默认值是
**`false`**,整形和浮点型变量默认值是零,字符串型变量(例如用于 [echo](https://www.php.net/manual/zh/function.echo.php) 
中)默认值是空字符串以及数组变量的默认值是空数组。

示例 #1 未初始化变量的默认值


<?php
// 未设置和未引用(不使用上下文)的变量;输出 NULL
var_dump($unset_var);

// Boolean 用法;输出 'false' (See ternary operators for more on this syntax)
echo $unset_bool ? "true\n" : "false\n";

// String 用法;输出 'string(3) "abc"'
$unset_str .= 'abc';
var_dump($unset_str);

// Integer 用法;输出 'int(25)'
$unset_int += 25; // 0 + 25 => 25
var_dump($unset_int);

// Float 用法;输出 'float(1.25)'
$unset_float += 1.25;
var_dump($unset_float);

// Array 用法;输出 array(1) {  [3]=>  string(3) "def" }
$unset_arr[3] = "def"; // array() + array(3 => "def") => array(3 => "def")
var_dump($unset_arr);

// Object 用法:创建新 stdClass 对象 (see http://www.php.net/manual/en/reserved.classes.php)
// Outputs: object(stdClass)#1 (1) {  ["foo"]=>  string(3) "bar" }
$unset_obj->foo = 'bar';
var_dump($unset_obj);
?>

依赖未初始化变量的默认值在某些情况下会有问题,例如把一个文件包含到另一个之中时碰上相同的变量名。

使用未初始化的变量会发出
**`E_WARNING`** (在 PHP 8.0.0 之前是 **`E_NOTICE`**)
错误,但是在向一个未初始化的数组附加单元时不会。[isset()](https://www.php.net/manual/zh/function.isset.php) 语言结构可以用来检测一个变量是否已被初始化。

预定义变量

对于全部脚本而言,PHP 提供了大量的预定义变量。这些变量将所有的外部变量表示成内建环境变量,并且将错误信息表示成返回头。

目录

变量范围

变量的范围即它定义的上下文背景(也就是它的生效范围)。大部分的
PHP 变量只有一个单独的范围。这个单独的范围跨度同样包含了
include 和 require 引入的文件。例如:

<?php
$a = 1;
include 'b.inc';
?>
这里变量 $a 将会在包含文件
b.inc 中生效。但是,在用户自定义函数中,一个局部函数范围将被引入。任何用于函数内部的变量按缺省情况将被限制在局部函数范围内。例如:

<?php
$a = 1; /* global scope */

function Test()
{
    echo $a; /* reference to local scope variable */
}

Test();
?>
这个脚本不会有任何输出,因为 echo 语句引用了一个局部版本的变量
$a,而且在这个范围内,它并没有被赋值。你可能注意到
PHP 的全局变量和 C 语言有一点点不同,在 C
语言中,全局变量在函数中自动生效,除非被局部变量覆盖。这可能引起一些问题,有些人可能不小心就改变了一个全局变量。PHP
中全局变量在函数中使用时必须声明为 global。

global 关键字

首先,一个使用 global 的例子:

示例 #1 使用 global


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

function Sum()
{
    global $a, $b;

    $b = $a + $b;
}

Sum();
echo $b;
?>

以上脚本的输出将是“3”。在函数中声明了全局变量

 $a 和 $b
 之后,对任一变量的所有引用都会指向其全局版本。对于一个函数能够声明的全局变量的最大个数,PHP 没有限制。

在全局范围内访问变量的第二个办法,是用特殊的 PHP 自定义

 [$GLOBALS](https://www.php.net/manual/zh/reserved.variables.globals.php) 数组。前面的例子可以写成:

示例 #2 使用 $GLOBALS 替代 global


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

function Sum()
{
    $GLOBALS['b'] = $GLOBALS['a'] + $GLOBALS['b'];
}

Sum();
echo $b;
?>

$GLOBALS

 是一个关联数组,每一个变量为一个元素,键名对应变量名,值对应变量的内容。[$GLOBALS](https://www.php.net/manual/zh/reserved.variables.globals.php)
 之所以在全局范围内存在,是因为 $GLOBALS 是一个[超全局变量](https://www.php.net/manual/zh/language.variables.superglobals.php)。以下范例显示了超全局变量的用处:

示例 #3 演示超全局变量和作用域的例子


<?php
function test_superglobal()
{
    echo $_POST['name'];
}
?>

使用静态变量

变量范围的另一个重要特性是静态变量(static

 variable)。静态变量仅在局部函数域中存在,但当程序执行离开此作用域时,其值并不丢失。看看下面的例子:

示例 #4 演示需要静态变量的例子


<?php
function Test()
{
    $a = 0;
    echo $a;
    $a++;
}
?>
 本函数没什么用处,因为每次调用时都会将
 $a 的值设为 `0` 并输出
 `0`。将变量加一的 $a++
 没有作用,因为一旦退出本函数则变量
 $a 就不存在了。要写一个不会丢失本次计数值的计数函数,要将变量
 $a 定义为静态的:

示例 #5 使用静态变量的例子


<?php
function test()
{
    static $a = 0;
    echo $a;
    $a++;
}
?>
 现在,变量 $a 仅在第一次调用 test() 函数时被初始化,之后每次调用 test() 函数都会输出
 $a 的值并加一。

 静态变量也提供了一种处理递归函数的方法。递归函数是一种调用自己的函数。写递归函数时要小心,因为可能会无穷递归下去。必须确保有充分的方法来中止递归。以下这个简单的函数递归计数到
 10,使用静态变量 $count 来判断何时停止:

示例 #6 静态变量与递归函数


<?php
function test()
{
    static $count = 0;

    $count++;
    echo $count;
    if ($count < 10) {
        test();
    }
    $count--;
}
?>
    常量表达式的结果可以赋值给静态变量,但是动态表达式(比如函数调用)会导致解析错误。
 

示例 #7 声明静态变量


<?php
function foo(){
    static $int = 0;          // 正确
    static $int = 1+2;        // 正确
    static $int = sqrt(121);  // 错误(因为它是函数)

    $int++;
    echo $int;
}
?>
从 PHP 8.1.0
开始,当继承(不是覆盖)使用有静态变量的方法时,继承的方法将会跟父级方法共享静态变量。这意味着方法中的静态变量现在跟静态属性有相同的行为。

示例 #8 在继承方法中使用静态变量


<?php
class Foo {
    public static function counter() {
        static $counter = 0;
        $counter++;
        return $counter;
    }
}
class Bar extends Foo {}
var_dump(Foo::counter()); // int(1)
var_dump(Foo::counter()); // int(2)
var_dump(Bar::counter()); // int(3),PHP 8.1.0 之前 int(1)
var_dump(Bar::counter()); // int(4),PHP 8.1.0 之前 int(2)
?>

>注意:

 静态声明在编译时解析。

全局和静态变量的引用

对于变量的

 [static](https://www.php.net/manual/zh/language.variables.scope.php#language.variables.scope.static) 和
 [global](https://www.php.net/manual/zh/language.variables.scope.php#language.variables.scope.global)
 定义是以[引用](https://www.php.net/manual/zh/language.references.php)的方式实现的。例如,在一个函数域内部用
 `global`
 语句导入的一个真正的全局变量实际上是建立了一个到全局变量的引用。这有可能导致预料之外的行为,如以下例子所演示的:


<?php
function test_global_ref() {
    global $obj;
    $new = new stdClass;
    $obj = &$new;
}

function test_global_noref() {
    global $obj;
    $new = new stdClass;
    $obj = $new;
}

test_global_ref();
var_dump($obj);
test_global_noref();
var_dump($obj);
?>

以上示例会输出:

NULL
object(stdClass)#1 (0) {
}
 类似的行为也适用于
 `static` 语句。引用并不是静态地存储的:


<?php
function &get_instance_ref() {
    static $obj;

    echo 'Static object: ';
    var_dump($obj);
    if (!isset($obj)) {
        $new = new stdClass;
        // 将一个引用赋值给静态变量
        $obj = &$new;
    }
    if (!isset($obj->property)) {
        $obj->property = 1;
    } else {
        $obj->property++;
    }
    return $obj;
}

function &get_instance_noref() {
    static $obj;

    echo 'Static object: ';
    var_dump($obj);
    if (!isset($obj)) {
        $new = new stdClass;
        // 将一个对象赋值给静态变量
        $obj = $new;
    }
    if (!isset($obj->property)) {
        $obj->property = 1;
    } else {
        $obj->property++;
    }
    return $obj;
}

$obj1 = get_instance_ref();
$still_obj1 = get_instance_ref();
echo "\n";
$obj2 = get_instance_noref();
$still_obj2 = get_instance_noref();
?>

以上示例会输出:

Static object: NULL
Static object: NULL

Static object: NULL
Static object: object(stdClass)#3 (1) {
  ["property"]=>
  int(1)
}

上例演示了当把一个引用赋值给一个静态变量时,第二次调用

 `&get_instance_ref()` 函数时其值并没有被记住。

可变变量

有时候使用可变变量名是很方便的。就是说,一个变量的变量名可以动态的设置和使用。一个普通的变量通过声明来设置,例如:


<?php
$a = 'hello';
?>
一个可变变量获取了一个普通变量的值作为这个可变变量的变量名。在上面的例子中
hello 使用了两个美元符号($)以后,就可以作为一个可变变量的变量了。例如:

<?php
$$a = 'world';
?>
这时,两个变量都被定义了:$a 的内容是“hello”并且
$hello 的内容是“world”。因此,以下语句:

<?php
echo "$a {$$a}";
?>
与以下语句输出完全相同的结果:

<?php
echo "$a $hello";
?>
它们都会输出:hello world。
要将可变变量用于数组,必须解决一个模棱两可的问题。这就是当写下
$$a[1]
时,解析器需要知道是想要
$a[1]
作为一个变量呢,还是想要
$$a
作为一个变量并取出该变量中索引为 [1]
的值。解决此问题的语法是,对第一种情况用
${$a[1]},对第二种情况用
${$a}[1]。
类的属性也可以通过可变属性名来访问。可变属性名将在该调用所处的范围内被解析。例如,对于
$foo->$bar 表达式,则会在本地范围来解析 $bar
并且其值将被用于 $foo 的属性名。对于 $bar
是数组单元时也是一样。

也可使用花括号来给属性名清晰定界。最有用是在属性位于数组中,或者属性名包含有多个部分或者属性名包含有非法字符时(例如来自

[json_decode()](https://www.php.net/manual/zh/function.json-decode.php) 或 [SimpleXML](https://www.php.net/manual/zh/book.simplexml.php))。

示例 #1 可变属性示例


<?php
class foo {
    var $bar = 'I am bar.';
    var $arr = array('I am A.', 'I am B.', 'I am C.');
    var $r   = 'I am r.';
}

$foo = new foo();
$bar = 'bar';
$baz = array('foo', 'bar', 'baz', 'quux');
echo $foo->$bar . "\n";
echo $foo->{$baz[1]} . "\n";

$start = 'b';
$end   = 'ar';
echo $foo->{$start . $end} . "\n";

$arr = 'arr';
echo $foo->{$arr[1]} . "\n";

?>

以上示例会输出:

I am bar.

I am bar.

I am bar.

I am r.

警告

注意,在 PHP 的函数和类的方法中,超全局变量不能用作可变变量。$this

 变量也是一个特殊变量,不能被动态引用。