类型
简介
PHP 支持 10 种原始数据类型
四种标量类型:
- bool(布尔型)
- int(整型)
- float(浮点型,也称作 double)
- string(字符串)
四种复合类型:
- array(数组)
- object(对象)
- callable(可调用)
- iterable(可迭代)
两种特殊类型:
“双精度(double)”类型,实际上和 float 是相同的,由于一些历史的原因,这两个名称同时存在。 得到一个易读懂的类型的表达方式,用 gettype() 函数。要检验某个类型,用 is_type 函数。
Boolean 布尔类型
bool 表达了真值,可以为 true 或 false,两个都不区分大小写。
转换为布尔值
- 用 (bool) 或者 (boolean) 来强制转换
- 自动转换
当转换为 bool 时,以下值被认为是 false:
- 布尔值 false 本身
- 整型值 0(零)
- 浮点型值 0.0(零)-0.0(零)
- 空字符串,以及字符串 “0”
- 不包括任何元素的数组
- 特殊类型 NULL(包括尚未赋值的变量)
- 由无属性的空元素创建 SimpleXML 对象,也就是既没有子节点也没有属性的元素。
所有其它值都被认为是 true(包括任何资源 和 NAN)。
字符串’0.0’,-1 和其它非零值(不论正负),被认为是 true!
Integer 整型
整型值 int 可以使用十进制,十六进制,八进制或二进制表示,前面可以加上可选的符号(- 或者 +)。 可以用 负运算符 来表示一个负的int。 要使用八进制表达,数字前必须加上 0(零)。 PHP 8.1.0 起,八进制表达也可以在前面加上 0o 或者 0O 。 要使用十六进制表达,数字前必须加上 0x。要使用二进制表达,数字前必须加上 0b。 PHP 7.4.0 开始,整型数值可能会包含下划线 (_) 整型数 int 的字长和平台有关。64 位平台下的最大值通常是大约 9E18。 PHP 不支持无符号的 int。int 值的字长可以用常量 PHP_INT_SIZE来表示, 最大值可以用常量 PHP_INT_MAX 来表示, 最小值可以用常量 PHP_INT_MIN 表示。
整数溢出
如果给定的一个数超出了 int 的范围,将会被解释为 float。同样如果执行的运算结果超出了 int 范围,也会返回 float。 PHP 没有 int 除法取整运算符,要使用 intdiv() 实现。 1/2 产生出 float 0.5。强制转换为 int,值会舍弃小数部分。使用 round() 函数会地进行四舍五入。
intdiv(int $dividend, int $divisor): int
- dividend 除以 divisor ,对该商取整
- 如果 divisor 是 0,将抛出 DivisionByZeroError 异常
- 如果 dividend 是 PHP_INT_MIN 并且 divisor 是 -1,将抛出 ArithmeticError 异常
转换为整型
- 用 (int) 或 (integer) 强制转换
- intval() 将一个值转换成 int 整型
- 自动转换
从布尔值转换
- false 将产生出 0(零),true 将产生出 1(壹)
从浮点型转换
- 当从浮点数 float 转换成整数 int 时,将向下取整。
- 如果浮点数超出了 int 范围,结果为未定义
- NaN 和 Infinity 在转换成 int 时是零
- 将未知的分数强制转换为 int,这样有时会导致不可预料的结果
从字符串转换
- 如果 string 是 numeric 或者前导数字, 则将它解析为相应的 int 值,否则将转换为零(0)
从 NULL 转换
从其它类型转换
Float 浮点型
浮点型(也叫浮点数 float,双精度数 double 或实数 real)
浮点数的精度
浮点数的精度有限。非基本数学运算可能会给出更大误差,如果确实需要更高的精度,应该使用任意精度数学函数或者 gmp 函数。
- bcadd — 两个任意精度数字的加法计算
- bccomp — 比较两个任意精度的数字
- bcdiv — 两个任意精度的数字除法计算
- bcmod — 任意精度数字取模
- bcmul — 两个任意精度数字乘法计算
- bcpow — 任意精度数字的乘方
- bcpowmod — Raise an arbitrary precision number to another, reduced by a specified modulus
- bcscale — 设置/获取所有
- bc math 函数的默认小数点保留位数
- bcsqrt — 任意精度数字的二次方根
- bcsub — 两个任意精度数字的减法
转换为浮点数
从 string 转换
- 如果 string 是 numeric 或者前导数字, 则将它解析为相应的 float 值,否则将转换为零(0)
从其他类型转换
- 对于其它类型的值,其情况类似于先将值转换成 int,然后再转换成 float
比较浮点数
要使用一个仅比该数值大一丁点的最小误差值。该值也被称为机器极小值(epsilon)或最小单元取整数,是计算中所能接受的最小的差别值。
<?php
$a = 1.23456789;
$b = 1.23456780;
$epsilon = 0.00001;
if(abs($a-$b) < $epsilon) {
echo "true";
}
?>
NaN
某些数学运算会产生一个由常量 NAN 所代表的结果。此结果代表着一个在浮点数运算中未定义或不可表述的值。任何拿此值与其它任何值(除了 true)进行的松散或严格比较的结果都是 false。 由于 NAN 代表着任何不同值,不应拿 NAN 去和其它值进行比较,包括其自身,应该用 is_nan() 来检查。
String 字符串
一个字符串 string 就是由一系列的字符组成,其中每个字符等同于一个字节。这意味着 PHP 只能支持 256 的字符集,因此不支持 Unicode
语法
- 单引号
- 双引号
- heredoc 语法结构
没有双引号的双引号string PHP 7.3.0 之前的版本中,结束时所引用的标识符必须在该行的第一列 结束标识符的缩进不能超过正文的任何一行 缩进结束标识符和内容, 制表符和空格不能混合使用 内容字符串的结束标识符后面不需要跟分号或者换行符 不要选择正文内容中出现的词作为结束标识符
$str = <<<EOD
Example of string
spanning multiple lines
using heredoc syntax.
EOD;
class foo
{
var $foo;
var $bar;
function __construct()
{
$this->foo = 'Foo';
$this->bar = array('Bar1', 'Bar2', 'Bar3');
}
}
$foo = new foo();
$name = 'MyName';
echo <<<EOT
My name is "$name". I am printing some $foo->foo.
Now, I am printing some {$foo->bar[1]}.
This should print a capital 'A': \x41
EOT;
My name is “MyName”. I am printing some Foo. Now, I am printing some Bar2. This should print a capital ‘A’: A
- nowdoc 语法结构
单引号字符串
class foo
{
public $foo;
public $bar;
function __construct()
{
$this->foo = 'Foo';
$this->bar = array('Bar1', 'Bar2', 'Bar3');
}
}
$foo = new foo();
$name = 'MyName';
echo <<<'EOT'
My name is "$name". I am printing some $foo->foo.
Now, I am printing some {$foo->bar[1]}.
This should not print a capital 'A': \x41
EOT;
My name is “$name”. I am printing some $foo->foo.
Now, I am printing some {$foo->bar[1]}. This should not print a capital ‘A’: \x41
变量解析
- 简单规则
美元符号($) - 复杂规则
花括号 { 和 } 只有 $ 紧挨着 { 时才会被识别,用 {\ $ 来表达 {$
存取和修改字符串中的字符
- 可以通过一个从 0 开始的下标,用类似 array 结构中的方括号包含对应的数字来访问和修改,函数 substr() 和 substr_replace() 可用于操作多于一个字符的情况
- PHP 7.1.0 开始,支持 string 负偏移量,以前,负偏移量读取时(返回空 string)会发出 E_NOTICE, 写入时(string 保持不变)会发出E_WARNING。
- PHP 8.0.0 之前, 可以使用大括号访问 string,例如 $str{42}。PHP 7.4.0
起,此大括号语法被弃用,PHP 8.0.0 开始不再受支持 - PHP 7.1.0 开始,对空字符串应用空索引运算符会引发致命错误。 以前是空字符串会被静默转为数组
- 字符串下标必须为整数或可转换为整数的字符串,否则会发出警告
- 用 [] 或 {} 访问任何其它类型(不包括数组或具有相应接口的对象实现)的变量只会无声地返回 null
有用的函数和运算符
字符串可以用 ‘.’(点)运算符连接起来
转换成字符串
- (string) 或用 strval() 函数
- 自动转换
- 一个布尔值 bool 的 true 被转换成 string 的 “1”。bool 的 false 被转换成 “”(空字符串) 一个整数
- int 或浮点数 float 被转换为数字的字面样式的 string(包括 float
中的指数部分)。使用指数计数法的浮点数(4.1E+6)也可转换 - 数组 array 总是转换成字符串 “Array” 必须使用魔术方法
- __toString 才能将 object 转换为 string
- 资源 Resource 总会被转变成 “Resource id #1”,可以用函数 get_resource_type()
- null 总是被转变成空字符串
- 大部分的 PHP 值可以转变成 string 来永久保存,这被称作串行化,可以用函数 serialize() 来实现
字符串类型详解
PHP 中的 string 的实现方式是一个由字节组成的数组再加上一个整数指明缓冲区长度
数字字符串
如果一个 PHP string 可以被解释为 int 或 float 类型,则它被视为数字字符串 当一个 string 需要被当作一个数字计算时,(例如:算术运算, int 类型声明等),则采取以下步骤来确定结果:
- 如果 string 是数字,当 string 是整数字符串并且符合 int 类型的范围限制(即是 PHP_INT_MAX 定义的值),则解析为 int ,否则解析为 float 。
- 上下文允许前导数字和一个 string,如果 string 的前导部分是整数数字字符串且符合 int 类型限制(由 PHP_INT_MAX 定义),则解析为 int ,否则解析为 float 。 此外,还会导致 E_WARNING 级别的错误。
- 果 string 不是数字,则会抛出一个 TypeError 的异常。
PHP 8.0.0 之前的行为
在 PHP 8.0.0 之前, 只有在前导空格的时候,string 才被认为是数字;如果它有尾随空格,则该字符串被视为是前导数字。
在 PHP 8.0.0 之前,当在数字上下文中使用字符串时,它将执行与上述相同的步骤,但有以下区别:
- 使用前导数字字符串将导致 E_NOTICE 而不是 E_WARNING 错误。
- 如果字符串不是数字,则会导致 E_WARNING 错误并返回 0 。
在 PHP 7.1.0 之前,则既不会导致 E_NOTICE,也不会导致 E_WARNING。
Array 数组
语法
定义数组
key 可以是 integer 或者 string。value 可以是任意类型
- String 中包含有效的十进制 int,除非数字前面有一个 + 号,否则将被转换为 int 类型。
- Float 也会被转换为 int ,意味着其小数部分会被舍去。
- Bool 也会被转换成 int。
- Null 会被转换为空字符串,即键名 null 实际会被储存为 “”。
- Array 和 object 不能 被用为键名。坚持这么做会导致警告:Illegal offset type。
key 为可选项。如果未指定,PHP 将自动使用之前用过的最大 int 键名加上 1 作为新的键名
用方括号语法访问数组单元
数组单元可以通过 array[key] 语法来访问 试图访问一个未定义的数组键名与访问任何未定义变量一样:会导致 E_NOTICE 级别错误信息,其结果为 null。
用方括号的语法新建/修改
在方括号内指定键名来给 array 赋值实现的。也可以省略键名 PHP 7.1.0 起,对字符串应用空索引操作符会抛出致命错误。以前,字符串被静默地转换为数组。 PHP 8.1.0 起,弃用从 false 值中创建一个新数组。 但仍然允许从 null 或者未定义的变量中创建新数组 要修改某个值,通过其键名给该单元赋一个新值。要删除某键值对,对其调用 unset() 函数 如果给出方括号但没有指定键名,则取当前最大 int 索引值,新的键名将是该值加上 1(但是最小为 0)。如果当前还没有 int 索引,则键名将为 0
实用函数
unset() 函数允许删除 array 中的某个键,数组将不会重建索引 array_values() 函数重建 array 索引
转换为数组
- 对于任意 int,float, string,bool 和 resource 类型,如果将一个值转换为 array,将得到一个仅有一个元素的数组,其下标为 0,该元素即为此标量的值
- object 类型转换为 array,则结果为一个数组,其单元为该对象的属性
比较
array_diff() 函数
返回一个数组,该数组包括了所有在 array 中但是不在任何其它参数数组中的值,保留数组 array 里的键
数组运算符
例子 | 名称 | 结果 |
---|
$a + $b | 联合 | $a 和 $b 的联合 | $a == $b | 相等 | 如果 $a 和 $b 具有相同的键/值对则为 true | $a === $b | 全等 | 如果 $a 和 $b 具有相同的键/值对并且顺序和类型都相同则为 true | $a != $b | 不等 | 如果 $a 不等于 $b 则为 true | $a <> $b | 不等 | 如果 $a 不等于 $b 则为 true | $a !== $b | 不全等 | 如果 $a 不全等于 $b 则为 true |
数组解包
在 array 定义时,用 … 前缀的一个 array 可以被展开到当前位置,PHP 7.4.0 开始可以使用 … 操作符解包 array 时也遵守函数 array_merge() 的语义。key 为字符时,后面的字符键会覆盖之前的字符键;key 为 integer 时则会重新编号 既不是 integer 也不是 string 的 key 会抛出 TypeError 在 PHP 8.1 之前,带有 string 键的 array 无法解包
Iterable 可迭代对象
PHP 7.1 中引入的一个伪类型,可迭代对象可以用作参数类型,表示函数需要一组值, 但是不会关心值集的形式,还可以用作返回类型,表示函数将返回一个可迭代的值
Object 对象
对象初始化
要创建一个新的对象 object,使用 new 语句实例化一个类
转换为对象
- 如果将一个对象转换成对象,它将不会有任何变化。
- 如果其它任何类型的值被转换成对象,将会创建一个内置类 stdClass 的实例。
- 如果该值为 null,则新的实例为空。
- array 转换成 object 将使键名成为属性名并具有相对应的值
- PHP 7.2.0 之前的版本,数字键只能通过迭代访问
- 其他值,会包含进成员变量名 scalar
- 例子:
$bar = 'string';
var_dump((object)$bar);
object(stdClass)
["scalar"]=>
string(6) "string"
}
Enum 枚举
(PHP 8 >= 8.1.0)
枚举基础
基础上的约束层, 目标是提供一种能力:定义包含可能值的封闭集合类型
类型转换
- 将 enum 转换为 object 不会有变化。
- 将 enum 转换为 array, 纯粹枚举会创建单个 name 键的数组; 回退枚举创建带 name 和 value 键的数组。
- 其他类型转换都会导致错误
<?php
enum Suit
{
case Hearts;
case Diamonds;
case Clubs;
case Spades;
}
function do_stuff(Suit $s)
{
}
do_stuff(Suit::Spades);
?>
Resource 资源类型
资源 resource 是一种特殊变量,保存了到外部资源的一个引用。资源是通过专门的函数来建立和使用的
转换为资源
由于资源类型变量保存有为打开文件、数据库连接、图形画布区域等的特殊句柄,因此将其它类型的值转换为资源没有意义
释放资源
引用计数系统是 Zend 引擎的一部分,可以自动检测到一个资源不再被引用了(和 Java 一样)。这种情况下此资源使用的所有外部资源都会被垃圾回收系统释放。因此,很少需要手工释放内存
NULL
特殊的 null 值表示一个变量没有值。NULL 类型唯一可能的值就是 null。 在下列情况下一个变量被认为是 null:
- 被赋值为 null。
- 尚未被赋值。
- 被 unset()。
语法
null 类型只有一个值,就是不区分大小写的常量 null。
<?php
$var = NULL;
?>
参见 is_null() 和 unset()
转换到 NULL
本特性自 PHP 7.2.0 起废弃,并且自 PHP 8.0.0 起被移除 使用 (unset) $var 将一个变量转换为 null 将不会删除该变量或 unset 其值。仅是返回 null 值而已
Callback / Callable 类型
回调可以通过 callable 类型声明来表示
传递
PHP是将函数以string形式传递的。 可以使用任何内置或用户自定义函数,但除了语言结构例如:array(),echo,empty(),eval(),exit(),isset(),list(),print 或 unset()
<?php
function my_callback_function() {
echo 'hello world!';
}
class MyClass {
static function myCallbackMethod() {
echo 'Hello World!';
}
}
call_user_func('my_callback_function');
call_user_func(array('MyClass', 'myCallbackMethod'));
$obj = new MyClass();
call_user_func(array($obj, 'myCallbackMethod'));
call_user_func('MyClass::myCallbackMethod');
class A {
public static function who() {
echo "A\n";
}
}
class B extends A {
public static function who() {
echo "B\n";
}
}
call_user_func(array('B', 'parent::who'));
class C {
public function __invoke($name) {
echo 'Hello ', $name, "\n";
}
}
$c = new C();
call_user_func($c, 'PHP!');
$double = function($a) {
return $a * 2;
};
$numbers = range(1, 5);
$new_numbers = array_map($double, $numbers);
print implode(' ', $new_numbers);
类型声明
类型声明可以用于函数的参数、返回值,PHP 7.4.0 起还可以用于类的属性,来显性的指定需要的类型,如果预期类型在调用时不匹配,则会抛出一个 TypeError 异常
单一类型
类型 | 说明 | 版本 |
---|
类/接口 名称 | 值必须为指定类和接口的实例化对象 instanceof | | self | 值必须是用于类型声明相同类的 instanceof 。 仅可在类中使用。 | | parent | 值必须是用于类型声明父级类的 instanceof , 仅可在类中使用。 | | array | 值必须为 array。 | | callable | 值必定是一个有效的 callable。 不能用于类属性的类型声明。 | | bool | 值必须为一个布尔值。 | | float | 值必须为一个浮点数字。 | | int | 值必须为一个整型数字。 | | string | 值必须为一个 string。 | | iterable | 值必须为 array 或 instanceof Traversable。 | PHP 7.1.0 | object | 值必须为object。 | PHP 7.2.0 | mixed | 值可以为任何类型。 | PHP 8.0.0 |
mixed
mixed 等同于 联合类型 object|resource|array|string|int|float|bool|null。PHP 8.0.0 起可用
范例
<?php
class C {}
class D extends C {}
class E {}
function f(C $c) {
echo get_class($c)."\n";
}
f(new C);
f(new D);
f(new E);
interface I { public function f(); }
class C implements I { public function f() {} }
class E {}
function f(I $i) {
echo get_class($i)."\n";
}
f(new C);
f(new E);
function sum($a, $b): float {
return $a + $b;
}
var_dump(sum(1, 2));
class C {}
function getC(): C {
return new C;
}
var_dump(getC());
?>
允许为空的(Nullable)类型
PHP 7.1.0 起,类型声明允许前置一个问号 (?) 用来声明这个值允许为指定类型,或者为 null
<?php
class C {}
function f(?C $c) {
var_dump($c);
}
f(new C);
f(null);
object(C)
}
NULL
function get_item(): ?string {
if (isset($_GET['item'])) {
return $_GET['item'];
} else {
return null;
}
}
联合类型
联合类型接受多个不同的类型做为参数。声明联合类型的语法为 T1|T2|…。联合类型自 PHP 8.0.0 起可用
允许为空的联合类型
null 类型允许在联合类型中使用,例如 T1|T2|null 代表接受一个空值为参数。已经存在的 ?T 语法可以视为以下联合类型的一个简写 T|null null 不能作为一个独立的类型使用
false 伪类型
通过联合类型支持字面类型(Literal Type)false, 出于历史原因,很多内部函数在失败时返回了 false 而不是 null。 这类函数的典型例子是 strpos() false 不能单独作为类型使用(包括可空 nullable 类型)。 因此,false、false|null、 ?false 都是不可以用的 true 字面类型不存在
重复冗余的类型
为了能在联合类型声明中暴露简单的 bug,不需要加载 class 就可以在编译时让重复冗余的类型产生错误。 包含:
- 解析出来的类型只能出现一次。例如这样的类型 int|string|INT 会导致错误。
- 使用了 bool 时就不能再附带使用 false。
- 使用了 object 时就不能再附带使用 class 类型。
- 使用了 iterable 时,array、 Traversable 都不能再附带使用。
不过它不能确保类型最小化,因为要达到这样的效果,还要加载使用类型的 class 例如,假设 A 和 B 都是一个类的别名, 而 A|B 仍然是有效的,哪怕它可以被简化为 A 或 B。 同样的,如果 B extends A {},那 A|B 仍然是有效的联合类型,尽管它可以被简化为 A。
<?php
function foo(): int|INT {}
function foo(): bool|false {}
use A as B;
function foo(): A|B {}
class_alias('X', 'Y');
function foo(): X|Y {}
?>
仅仅返回类型
void
void 是一个返回类型,用于标识函数没有返回值。 它不能是联合类型的一部分。 PHP 7.1.0 起可用 PHP 8.1.0 起弃用引用返回 void 的函数, 因为这样的函数是矛盾的
never
never 是一种表示没有返回的返回类型。这意味着它可能是调用 exit(), 抛出异常或者是一个无限循环。所以,它不能作为联合类型的一部分。PHP 8.1.0 起可用。
在类型理论用于中,never 是底层类型。 意味着它是其它所有类型的子类型,并且可以在继承期间替换任何其他返回类型。
static
它的值必须是一个 class 的 instanceof,该 class 是调用方法所在的同一个类。 PHP 8.0.0 起有效。
严格类型
PHP 会强制转化不合适的类型为想要的标量类型。 比如,参数想要 string,传入的是 int, 则会获取 string 类型的变量 可以按文件开启严格模式。 在严格模式下,只能接受完全匹配的类型,否则会抛出 TypeError。 唯一的例外是 int 值也可以传入声明为 float 的类型 通过内部函数调用函数时,不会受 strict_types 声明影响 要开启严格模式,使用 declare 开启 strict_types: 注意: 文件开启严格类型后的内部调用函数将应用严格类型, 而不是在声明函数的文件内开启。 如果文件没有声明开启严格类型,而被调用的函数所在文件有严格类型声明, 那将遵循调用者的设置(开启类型强制转化), 值也会强制转化。 注意: 只有为标量类型的声明开启严格类型。
<?php
declare(strict_types=1);
function sum(int $a, int $b) {
return $a + $b;
}
var_dump(sum(1, 2));
var_dump(sum(1.5, 2.5));
?>
联合类型的内部隐式强制转化
没有开启 strict_types 时,标量类型可能会限制内部隐式类型转化。 如果值的类型不是联合类型中的一部分,则目标类型会按以下顺序:
- int
- float
- string
- bool
如果类型出现在组合中,值可以按 PHP 现有的类型语义检测进行内部隐式强制转化,则会选择该类型。 否则会尝试下一个类型。 警告 有一个例外:当值是字符串,而 int 与 float 同时在组合中,将按现有的“数字字符串”检测语义,识别首选的类型。 例如,“42” 会选择 int 类型, 而 “42.0” 会选择 float 类型。 注意 没有出现在上面列表中的类型则不是有效的内部隐式转化目标。 尤其是不会出现内部隐式转化 null 和 false 类型。
<?php
42 --> 42
"42" --> "42"
new ObjectWithToString --> "__toString() 的结果"
42.0 --> 42
42.1 --> 42
1e100 --> "1.0E+100"
INF --> "INF"
true --> 1
[] --> TypeError
"45" --> 45
"45.0" --> 45.0
"45X" --> true
"" --> false
"X" --> true
[] --> TypeError
?>
其他
示例 #12 传引用参数的类型
仅仅会在函数入口检查传引用的参数类型,而不是在函数返回时检查。 所以函数返回时,参数类型可能会发生变化。
<?php
function array_baz(array &$param)
{
$param = 1;
}
$var = [];
array_baz($var);
var_dump($var);
array_baz($var);
?>
类型转换的判别
PHP 在变量定义中不需要(或不支持)明确的类型定义;变量类型是根据使用该变量的上下文所决定的
类型强制转换
在要转换的变量之前加上用括号括起来的目标类型 允许的强制转换有:
- (int), (integer) - 转换为整形 int
- (bool), (boolean) - 转换为布尔类型 bool
- (float), (double), (real) - 转换为浮点型 float
- (string) - 转换为字符串 string
- (array) - 转换为数组 array
- (object) - 转换为对象 object
- (unset) - 转换为 NULL
向前兼容 (binary) 转换和 b 前缀转换。注意 (binary) 转换和 (string) 基本相同,但是不应该依赖它。
(unset) 转换在 PHP 7.2.0 中已被废弃。请注意 (unset) 转换等于将值赋予 NULL。(unset) 转换已经在 PHP 8.0.0 中被移除。
注意在括号内允许有空格和制表符,所以下面两个例子功能相同:
<?php
$foo = (int) $bar;
$foo = ( int ) $bar;
?>
变量
预定义变量
PHP 提供了大量的预定义变量 PHP 提供了一套附加的预定数组,这些数组变量包含了来自 web 服务器(如果可用),运行环境,和用户输入的数据,它们在全局范围内自动生效
变量范围
变量的范围即它定义的上下文背景(也就是它的生效范围)。大部分的 PHP 变量只有一个单独的范围。这个单独的范围跨度同样包含了 include 和 require 引入的文件
global 关键字
$a = 1;
$b = 2;
function Sum()
{
global $a, $b;
$b = $a + $b;
}
function Sum()
{
$GLOBALS['b'] = $GLOBALS['a'] + $GLOBALS['b'];
}
Sum();
echo $b;
使用静态变量
变量范围的另一个重要特性是静态变量(static variable)。静态变量仅在局部函数域中存在,但当程序执行离开此作用域时,其值并不丢失
function test()
{
static $a = 0;
echo $a;
$a++;
}
赋值给静态变量,但是动态表达式(比如函数调用)会导致解析错误 静态声明是在编译时解析的
全局和静态变量的引用
对于变量的 static 和 global 定义是以引用的方式实现的。例如,在一个函数域内部用 global 语句导入的一个真正的全局变量实际上是建立了一个到全局变量的引用。这有可能导致预料之外的行为
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)
}
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)
["property"]=>
int(1)
}
可变变量
一个变量的变量名可以动态的设置和使用
来自 PHP 之外的变量
- HTML 表单(GET 和 POST)
- IMAGE SUBMIT 变量名
- HTTP Cookies
|