变量

概览

变量 是一个存储数据的命名区域,包含一个 PHP 值。变量由 VSlot 表示。变量通过对其赋值来创建。变量通过取消设置来销毁,无论是通过对unset 语句的显式调用,还是由引擎。内在的isset 测试给定的变量是否存在且未设置为 NULL。如果在表达式中使用了一个到目前为止未定义的变量,则将应用不同的策略来确定该变量是隐式定义的还是使用替代值,以及是否发出通知。这些策略取决于变量的类型以及使用未定义变量的上下文。这些策略在下面不同变量类型的小节中详细说明。

变量具有名称。不同的变量可以具有相同的名称,前提是它们在不同的作用域中。

一个常量是一个变量,一旦初始化,它的值就不能改变。

根据声明变量的上下文,变量具有作用域存储期.

超级全局变量是一个全局变量,无需全局声明 就可以在所有作用域中访问。

以下类型的变量可能存在于脚本中

变量类型

常量

语法

参见常量部分.

约束

在类或接口之外,c-常量只能在脚本的顶层定义。

语义

参见常量类常量.

在类或接口之外定义的常量是一个超级全局。常量具有静态的存储期 并且是一个不可修改的左值。

未定义的常量

未定义的常量不会被隐式定义 - 常量的向前使用也被归类为未定义的常量。类/接口常量和顶层常量之间有区别。

对于顶层常量:对于非限定的使用,未定义常量的名称(作为字符串)用作替代值。此外,会发出警告,说明相应的常量未定义。对于限定的使用,将抛出类型为Error 的异常。

对于类/接口常量:会抛出类型为Error 的异常,说明相应的常量未定义。

示例

const MAX_HEIGHT = 10.5;        // define two c-constants
const UPPER_LIMIT = MAX_HEIGHT;
define('COEFFICIENT_1', 2.345); // define two d-constants
define('FAILURE', TRUE);

// Examples of undefined constants
echo NON_EXISTING_CONSTANT;     // uses 'NON_EXISTING_CONSTANT' as substitution
                                // value and emits a warning stating that the
                                // constant was undefined.

echo NON_EXISTING_CONSTANT;     // same here, the constant is still undefined
                                // and 'NON_EXISTING_CONSTANT' is used as
                                // substitution value and a warning is emitted
                                // again.

echo MAX_LENGTH;                // same here due to a forward usage
                                // (MAX_LENGTH is defined further below).
                                // 'MAX_LENGTH' is used as substitution
                                // value and a warning is emitted.

echo \NON_EXISTING_CONSTANT;    // qualified use of undefined constant. Throws
                                // an exception of type Error.

const MAX_LENGTH = 7.5;

echo Exception::MESSAGE;        // undefined class constant. Throws an exception
                                // of type Error.

局部变量

语法

参见下面的语义。

语义

除了参数之外,局部变量永远不会被显式定义;相反,它是在第一次为它赋值时创建的。局部变量可以在函数定义的参数列表中或在任何复合语句中作为参数赋值。它具有函数作用域 和 自动存储期。局部变量是一个可修改的左值。

示例

function doit($p1)  // assigned the value TRUE when called
{
  $count = 10;
    ...
  if ($p1)
  {
    $message = "Can't open master file.";
    ...
  }
  ...
}
doit(TRUE);
// -----------------------------------------
function f()
{
  $lv = 1;
  echo "\$lv = $lv\n";
  ++$lv;
}
for ($i = 1; $i <= 3; ++$i)
  f();

函数静态等价物 不同,函数 f 每次都会输出“$lv = 1”。

参见存储期部分 中的递归函数示例。

未定义的局部变量

根据使用未定义局部变量的上下文,将进行区分。

按值上下文

PHP 不会隐式定义未定义的局部变量,而是使用 NULL 作为替代值。此外,会发出通知,说明相应的变量未定义,除非变量被使用

  1. 作为语句中的单个表达式。
  2. 作为isset 的参数。
  3. 作为empty 的参数。
  4. 作为合并运算符 ?? 的左侧。

由于未定义的局部变量不会被隐式定义,因此它们保持未定义。通常,不会为按值上下文中使用的未定义变量创建 VSlot。

按引用上下文

如果在按引用上下文中使用未定义的变量,则 PHP 会隐式定义该变量。因此,会为它创建 VSlot,并将 NULL 存储在其中。在这种情况下,不会发出通知。

未定义变量的示例

以下是一些示例,概述了对未定义局部变量的行为。

// The following 4 cases outline the exceptions of undefined variables
// used in byValue context where no notice is emitted.
$a;
isset($a);
empty($a);
$a ?? 'default Value';

$a = 1;    // a VSlot for $a was created and 1 was assigned.

$b = $c;   // a VSlot for $b was created and the value of $c was assigned to
           // it. But because $c in turn was undefined, NULL was used as
           // substitution value instead. In addition, a notice was
           // emitted stating that $c was undefined.

$d = $c;   // a VSlot for $d was created and the value of $c was assigned to
           // it. But since $c is still undefined, NULL was used as
           // substitution value instead and another notice was emitted
           // stating $c was undefined.

$d + $e;   // $e was undefined and `NULL` was used as substitution value
           // instead. In addition, a notice was emitted stating that
           // $e was undefined.

$f = &$g;  // a VSlot for $f was created which points to the VSlot of $g.
           // $g in turn was undefined but was defined implicitly because the
           // assignment was byRef. Thus a VSlot for $g was created and `NULL`
           // was assigned to it. A notice was *not* emitted.

$h = $g;   // a VSlot for $h was created and the value of $g (which is NULL)
           // was assigned to it.

function foo($x){}

foo($i);   // $i was undefined and NULL was used as substitution value
           // instead. In addition, a notice was emitted stating that $i
           // was undefined.

$j = $i;   // a VSlot for $j was created and the value of $i was assigned to
           // it. But because $i in turn was still undefined, NULL was used
           // as substitution value instead. Another notice was emitted
           // stating that $i was undefined.

function bar(&$x){}

bar($k);   // $k was undefined but implicitly defined because it was passed to
           // the function bar byRef. Thus a VSlot for $k was created and
           // NULL was assigned to it. A notice was *not* emitted.

$l = $k;   // a VSlot for $l was created and the value of $k (which is NULL)
           // was assigned to it.

数组元素

语法

数组 是使用数组创建运算符 创建的。同时,可以为该数组创建一个或多个元素。新元素通过结合下标运算符 []简单赋值运算符 插入到现有数组中。可以通过调用unset 语句 来删除元素。

语义

数组元素的作用域 与该数组名称的作用域相同。数组元素具有分配的存储期.

未定义的数组元素

类似于未定义的局部变量,根据使用未定义数组元素的上下文进行区分。

按值上下文

如果尝试访问未定义的数组元素,则使用 NULL 作为替代值,并发出通知,说明使用了未定义的偏移量。未定义的偏移量不会被隐式创建,后续访问会导致另一个通知。

按引用上下文

当按引用访问未定义的数组元素时,PHP 会隐式定义它,会为相应的未定义偏移量创建 VSlot,并将 NULL 分配给它。在这种情况下,不会发出通知。

示例

$colors = ["red", "white", "blue"]; // create array with 3 elements
$colors[] = "green";                // insert a new element

echo $colors[100];      // element with offset 100 is undefined and NULL is
                        // used as substitution value. Moreover, a notice is
                        // emitted stating that an undefined offset was used.

echo $colors[100];      // element with offset 100 is still undefined and NULL
                        // is used as substitution value instead. Another
                        // notice is emitted.

$b = &$colors[100];     // a VSlot for $b is created which points to the array
                        // element with the offset 100. An array element with
                        // offset 100 was undefined but implicitly defined
                        // because the assignment is byRef. Thus a VSlot for
                        // the array element with offset 100 is created and
                        // NULL is assigned to it. A notice is *not* emitted.

函数静态

语法

function-static-declaration:
   static   static-variable-name-list   ;

static-variable-name-list:
   static-variable-declaration
   static-variable-name-list   ,   static-variable-declaration

static-variable-declaration:
   variable-name   function-static-initializeropt

function-static-initializer:
   =   constant-expression

约束

函数静态必须在函数内部定义。

语义

函数静态可以在任何复合语句内部定义。它是一个可修改的左值。

函数静态具有函数作用域 和 静态存储期.

函数静态的值在对父函数的调用中保留。每次调用包含函数静态声明的函数时,该执行都在处理与该静态变量的别名。如果将该别名传递给unset 语句,则只会销毁该别名。下次调用该函数时,会创建一个新的别名。

未定义的函数静态

函数静态是显式定义的,因此不能是未定义的。

示例

function f()
{
  static $fs = 1;
  echo "\$fs = $fs\n";
  ++$fs;
}
for ($i = 1; $i <= 3; ++$i)
  f();

局部变量等价物 不同,函数 f 输出“$fs = 1”、“$fs = 2” 和 “$fs = 3”,因为 $fs 在调用之间保留其值。

还需要注意,声明函数静态可以隐藏具有相同名称的局部变量和/或全局变量。局部变量或全局变量的值不会作为函数静态的初始值使用。后续对该变量的修改只会修改函数静态,不会影响局部变量或全局变量。一个例子

function f(){
  $fs = 10;             // assign 10 to the local variable $fs
  static $fs;           // define a function static with name $fs
  echo "\$fs = $fs\n";  // $fs =
  $fs = 5;              // assign 5 to the function static $fs (local variable is not modified)
  echo "\$fs = $fs\n";  // $fs = 5
  global $fs;           // define a global variable with name $fs
  echo "\$fs = $fs\n";  // $fs =
  $fs = 3;              // assign 3 to the global variable $fs (function static and local variable is not modified
  echo "\$fs = $fs\n";  // $fs = 3
  static $fs;
  ++$fs;                // increment function static $fs
  echo "\$fs = $fs\n";  // $fs = 6
}
f();
echo "\$fs = $fs\n";    // $fs = 3

全局变量

语法

global-declaration:
   global   variable-name-list   ;

variable-name-list:
   simple-variable
   variable-name-list   ,   simple-variable

语义

全局变量永远不会被显式定义;相反,它是在第一次为它赋值时创建的。这可以在脚本的顶层完成,或者可以在使用 global 关键字声明(即导入)该变量的块中完成。

其中一个预定义变量$GLOBALS 是一个超级全局 数组,它的元素的键/值对分别包含当前定义的每个全局变量的名称和值。因此,全局变量 gv 可以使用以下赋值形式初始化为值 v,并可能被创建

$GLOBALS['gv'] = v

由于 $GLOBALS 是一个超级全局变量,因此 gv 不需要首先进行全局声明

全局变量具有全局的作用域 和 静态的存储期。全局变量是一个可修改的左值。

当全局值被导入到函数中时,每次调用函数时,该执行都在处理与该全局变量的别名。如果将该别名传递给unset 语句,则只会销毁该别名。下次调用该函数时,会使用全局变量的当前值创建一个新的别名。

未定义的全局变量

未定义的局部变量 相同的规则适用。

示例

$colors = array("red", "white", "blue");
$GLOBALS['done'] = FALSE;
// -----------------------------------------
$min = 10; $max = 100; $average = NULL;
global $min, $max;         // allowed, but serves no purpose
function compute($p)
{
  global $min, $max;
  global $average;
  $average = ($max + $min)/2;

  if ($p)
  {
    global $result;
    $result = 3.456;  // initializes a global, creating it, if necessary
  }
}
compute(TRUE);
echo "\$average = $average\n";  // $average = 55
echo "\$result = $result\n";  // $result = 3.456
// -----------------------------------------
$g = 100;
function f()
{
  $v = 'g';
  global $$v;          // import global $g
  ...
}

还需要注意,声明变量为全局变量可以隐藏具有相同名称的局部变量和/或函数静态。参见静态变量部分 以获取示例。

实例属性

这些在类实例属性部分 中有描述。它们具有定义类的类作用域 和 分配的存储期。对实例属性的访问受可见性规则 的控制。

静态属性

这些在类静态属性部分 中有描述。它们具有定义类的类作用域 和 静态的存储期。对静态属性的访问受可见性规则 的控制。

类和接口常量

这些在类常量部分接口常量部分 中有描述。它们具有定义类或接口的类作用域 和 静态的存储期.

预定义变量

以下全局变量对所有脚本可用

变量名称描述
$argcint; 传递给脚本的命令行参数的数量。至少为 1。(参见下面的 $argv)。这在引擎的非命令行构建中可能不可用。
$argvarray; 一个包含 $argc 个元素的数组,这些元素是作为字符串传递给脚本的命令行参数。每个元素都有一个 int 类型的键,键从零开始,依次递增到 $argc-1$argv[0] 是脚本的名称。命令行上空格的处理方式、字母大小写的保留方式、构成引号的字符以及 $argv[0] 字符串的格式都是由实现定义的。命令行参数的定义方式未指定。这可能在引擎的非命令行版本中不可用。
$_COOKIEarray; 通过 HTTP Cookie 传递给当前脚本的变量。
$_ENVarray; 一个数组,其中环境变量名称是元素键,环境变量值字符串是元素值。环境变量的定义方式未指定。
$_FILESarray; 通过 HTTP POST 方法上传到当前脚本的项目。
$_GETarray; 通过 URL 参数传递给当前脚本的变量。
$GLOBALSarray; 一个包含当前脚本全局作用域中所有已定义变量名称的 超级全局 数组。变量名称是元素键,变量值是元素值。
$_POSTarray; 通过 HTTP POST 方法传递给当前脚本的变量。
$_REQUESTarray; 默认情况下包含 $_COOKIE$_GET$_POST 的内容。确切的内容可能取决于引擎设置。
$_SERVERarray; 服务器和执行环境信息,例如标题、路径和脚本位置。此数组中的条目来自引擎环境,例如 Web 服务器。
$_SESSIONarray; 当前脚本可用的会话变量。只有在启用 会话 时才定义此全局变量。

上面所有 $_* 变量都是超级全局变量。可用的确切变量集可能取决于实现、引擎版本和环境。