PHP手册
PHP,即“PHP: Hypertext Preprocessor
” 超文本预处理语言,预处理即为解释型,脚本语言。
环境安装
Windows LTSC
phpstudy2016
语法参考
[SICP]指出,在学习一门编程语言时,要特别注意以下三方面:
- 这门语言提供了哪些Primitive,比如基本数据类型,比如基本的运算符、表达式和语句。
- 这门语言提供了哪些组合规则,比如复合数据类型,比如表达式和语句的组合规则。
- 这门语言提供了哪些抽象机制,例如数据抽象和过程抽象(Procedure Abstraction)。
基本语法
PHP标记
标记:<?php ?>,
短标记:<? ?>,激活 php.ini 中的 short_open_tag 配置指令或者在编译 PHP 时使用了配置选项 –enable-short-tags 时才能使用短标记。
ASP风格标记:<% %> ,php.ini 配置文件中的指令 asp_tags 打开后才可用。
如果文件内容是纯PHP代码,文件末尾的?>可以删除,避免加入额外的换行符。
此外注意如果将 PHP 嵌入到 XML 或 XHTML 中则需要使用 <?php ?> 标记以保持符合标准。
从HTML中分离
凡是在一对开始和结束标记之外的内容都会被 PHP 解析器忽略,这使得 PHP 文件可以具备混合内容。 可以使 PHP 嵌入到 HTML 文档中去。
<p>This is going to be ignored by PHP and displayed by the browser.</p>
<?php echo 'While this is going to be parsed.'; ?>
<p>This will also be ignored by PHP and displayed by the browser.</p>
当 PHP 解释器碰到 ?> 结束标记时就简单地将其后内容原样输出(除非马上紧接换行 - 见指令分隔符)直到碰到下一个开始标记;例外是处于条件语句中间时,此时 PHP 解释器会根据条件判断来决定哪些输出,哪些跳过。
<?php if ($expression == true): ?>
This will show if the expression is true.
<?php else: ?>
Otherwise this will show.
<?php endif; ?>
前2句PHP末尾都没有;结束符,所以可以连续执行。
上例中 PHP 将跳过条件语句未达成的段落,即使该段落位于 PHP 开始和结束标记之外。由于 PHP 解释器会在条件未达成时直接跳过该段条件语句块,因此 PHP 会根据条件来忽略之。
要输出大段文本时,跳出 PHP 解析模式通常比将文本通过 echo 或 print 输出更有效率。
<?php
echo "Hello PHP !";
?>
和
<?="Hello PHP !"?>
等效
自 PHP 5.4 起,短格式的 echo 标记
<?=
总会被识别并且合法,而不管 short_open_tag 的设置是什么。
指令分割符
同 C 或 Perl 一样,PHP 需要在每个语句后用分号结束指令。一段 PHP 代码中的结束标记隐含表示了一个分号;在一个 PHP 代码段中的最后一行可以不用分号结束。如果后面还有新行,则代码段的结束标记包含了行结束。
<?php
echo "This is a test";
?>
<?php echo "This is a test" ?>
<?php echo 'We omitted the last closing tag';
注释
PHP 支持 C,C++ 和 Unix Shell 风格(Perl 风格)的注释。例如:
<?php
echo "This is a test"; // This is a one-line c++ style comment
/* This is a multi line comment
yet another line of comment */
echo "This is yet another test";
echo 'One Final Test'; # This is a one-line shell-style comment
?>
单行注释仅仅注释到行末或者当前的 PHP 代码块,视乎哪个首先出现。这意味着在 // ... ?>
或者 # ... ?>
之后的 HTML 代码将被显示出来:?> 跳出了 PHP 模式并返回了 HTML 模式,//
或 #
并不能影响到这一点。如果启用了 asp_tags 配置选项,其行为和 // %>
或 # %>
相同。不过,</script>
标记在单行注释中不会跳出 PHP 模式。
类型
PHP是一种弱类型语言,因此导致了很多漏洞。
简介
PHP 支持 10 种原始数据类型。
四种标量类型:
- boolean(布尔型)
- integer(整型)
- float(浮点型,也称作 double)
- string(字符串)
四种复合类型:
最后是两种特殊类型:
- resource(资源)
- NULL(无类型)
为了确保代码的易读性,本手册还介绍了一些伪类型:
以及伪变量 $...
。
可能还会读到一些关于“双精度(double)”类型的参考。实际上 double 和 float 是相同的,由于一些历史的原因,这两个名称同时存在。
变量的类型通常不是由程序员设定的,确切地说,是由 PHP 根据该变量使用的上下文在运行时决定的。即为弱类型,因此会导致很多注入漏洞。
如果想查看某个表达式的值和类型,用 var_dump() 函数。如果只是想得到一个易读懂的类型的表达方式用于调试,用 gettype() 函数。要检验某个类型,不要用 gettype(),而用
is_type
函数。以下是一些范例:
<?php
$a_bool = TRUE; // 布尔值 boolean
$a_str = "foo"; // 字符串 string
$a_str2 = 'foo'; // 字符串 string
$an_int = 12; // 整型 integer
echo gettype($a_bool); // 输出: boolean
echo gettype($a_str); // 输出: string
// 如果是整型,就加上 4
if (is_int($an_int)) {
$an_int += 4;
}
// 如果 $bool 是字符串,就打印出来
// (啥也没打印出来)
if (is_string($a_bool)) {
echo "String: $a_bool";
}
?>
如果要将一个变量强制转换为某类型,可以对其使用强制转换或者 settype() 函数。
Boolean类型
boolean 表达了真值,可以为 TRUE
或 FALSE
。
语法
要指定一个布尔值,使用常量 TRUE
或 FALSE
。两个都不区分大小写。
<?php
$foo = True; // 设置 $foo 为 TRUE
?>
通常运算符所返回的 boolean 值结果会被传递给控制流程。
转换为布尔值
要明确地将一个值转换成 boolean,用 (bool)
或者 (boolean)
来强制转换。但是很多情况下不需要用强制转换,因为当运算符,函数或者流程控制结构需要一个 boolean 参数时,该值会被自动转换。
参见类型转换的判别。
当转换为 boolean 时,以下值被认为是 FALSE
:
- 布尔值
FALSE
本身 - 整型值 0(零)及 -0 (零)
- 浮点型值 0.0(零)-0.0(零)
- 空字符串,以及字符串 “0”
- 不包括任何元素的数组
- 特殊类型 NULL(包括尚未赋值的变量)
- 从空标记生成的 SimpleXML 对象
所有其它值都被认为是 TRUE
(包括任何资源 和 NAN
)。
Warning
-1
和其它非零值(不论正负)一样,被认为是TRUE
!
Integer 整型
integer 是集合 ℤ = {…, -2, -1, 0, 1, 2, …} 中的某个数。
语法
整型值可以使用十进制,十六进制,八进制或二进制表示,前面可以加上可选的符号(- 或者 +)。 可以用 负运算符 来表示一个负的integer。
二进制表达的 integer 自 PHP 5.4.0 起可用。
要使用八进制表达,数字前必须加上 0
(零)。要使用十六进制表达,数字前必须加上 0x
。要使用二进制表达,数字前必须加上 0b
。
从 PHP 7.4.0 开始,整型数值可能会包含下划线 (_
),为了更好的阅读体验,这些下划线在展示的时候,会被 PHP 过滤掉。
**Example #1 **整数文字表达
<?php
$a = 1234; // 十进制数
$a = 0123; // 八进制数 (等于十进制 83)
$a = 0x1A; // 十六进制数 (等于十进制 26)
$a = 0b11111111; // 二进制数字 (等于十进制 255)
$a = 1_234_567; // 整型数值 (PHP 7.4.0 以后)
?>
integer 语法的结构形式是(PHP 7.4.0 之前不支持下划线):
decimal : [1-9][0-9]*(_[0-9]+)*
| 0
hexadecimal : 0[xX][0-9a-fA-F]+(_[0-9a-fA-F]+)*
octal : 0[0-7]+(_[0-7]+)*
binary : 0[bB][01]+(_[01]+)*
integer : decimal
| hexadecimal
| octal
| binary
PHP 不支持无符号的 integer。Integer 值的字长可以用常量 **PHP_INT_SIZE
**来表示,自 PHP 4.4.0 和 PHP 5.0.5后,最大值可以用常量 PHP_INT_MAX
来表示,最小值可以在 PHP 7.0.0 及以后的版本中用常量 PHP_INT_MIN
表示。
Warning
PHP 7 以前的版本里,如果向八进制数传递了一个非法数字(即 8 或 9),则后面其余数字会被忽略。PHP 7 以后,会产生 Parse Error。
整数溢出
如果给定的一个数超出了 integer 的范围,将会被解释为 float。同样如果执行的运算结果超出了 integer 范围,也会返回 float。
PHP 中没有整除的运算符。1/2
产生出 float 0.5
。 值可以舍弃小数部分,强制转换为 integer,或者使用 round() 函数可以更好地进行四舍五入。
从 PHP 7.0.0 开始,函数 intdiv() 可以用于整数除法。
<?php
var_dump(25/7); // float(3.5714285714286)
var_dump((int) (25/7)); // int(3)
var_dump(round(25/7)); // float(4)
?>
从布尔值转换
FALSE
将产生出 0
(零),TRUE
将产生出 1
(壹)。
从浮点型转换
当从浮点数转换成整数时,将向下取整。
如果浮点数超出了整数范围(32 位平台下通常为 +/- 2.15e+9 = 2^31
,64 位平台下,除了 Windows 且版本低于 PHP 7,通常为 +/- 9.22e+18 = 2^63
),则结果为未定义,因为没有足够的精度给出一个确切的整数结果。在此情况下没有警告,甚至没有任何通知!
PHP 7.0.0 起,NaN 和 Infinity 在转换成 integer 时,不再是 undefined 或者依赖于平台,而是都会变成零。
Warning
绝不要将未知的分数强制转换为 integer,这样有时会导致不可预料的结果。
<?php echo (int) ( (0.1+0.7) * 10 ); // 显示 7! ?>
从字符串转换
参见字符串转换为数值。
这里就是一个弱类型,0e开始的md5。
从NULL转换
NULL
会转换为零 (0
)。
从其他类型转换
Caution
没有定义从其它类型转换为整型的行为。不要依赖任何现有的行为,因为它会未加通知地改变。
Float 浮点型
浮点型(也叫浮点数 float,双精度数 double 或实数 real)可以用以下任一语法定义:
<?php
$a = 1.234;
$b = 1.2e3;
$c = 7E-10;
$d = 1_234.567; // 从 PHP 7.4.0 开始支持
?>
浮点数的形式表示(PHP 7.4.0 之前不支持下划线):
LNUM [0-9]+(_[0-9]+)*
DNUM ([0-9]*(_[0-9]+)*[\.]{LNUM}) | ({LNUM}[\.][0-9]*(_[0-9]+)*)
EXPONENT_DNUM (({LNUM} | {DNUM}) [eE][+-]? {LNUM})
浮点数的字长和平台相关,尽管通常最大值是 1.8e308 并具有 14 位十进制数字的精度(64 位 IEEE 格式)。
Warning
浮点数的精度
浮点数的精度有限。尽管取决于系统,PHP 通常使用 IEEE 754 双精度格式,则由于取整而导致的最大相对误差为 1.11e-16。非基本数学运算可能会给出更大误差,并且要考虑到进行复合运算时的误差传递。
此外,以十进制能够精确表示的有理数如
0.1
或0.7
,无论有多少尾数都不能被内部所使用的二进制精确表示,因此不能在不丢失一点点精度的情况下转换为二进制的格式。这就会造成混乱的结果:例如,floor((0.1+0.7)*10)
通常会返回7
而不是预期中的8
,因为该结果内部的表示其实是类似7.9999999999999991118...
。所以永远不要相信浮点数结果精确到了最后一位,也永远不要比较两个浮点数是否相等。如果确实需要更高的精度,应该使用任意精度数学函数或者 gmp 函数。
参见» 浮点数指南网页的简单解释。
转换为浮点数
如果希望了解有关何时和如何将字符串转换成浮点数的信息,请参阅“字符串转换为数值”一节。对于其它类型的值,其情况类似于先将值转换成整型,然后再转换成浮点。请参阅“转换为整型”一节以获取更多信息。自 PHP 5 起,如果试图将对象转换为浮点数,会发出一条 E_NOTICE 错误消息。
比较浮点数
如上述警告信息所言,由于内部表达方式的原因,比较两个浮点数是否相等是有问题的。不过还是有迂回的方法来比较浮点数值的。
要测试浮点数是否相等,要使用一个仅比该数值大一丁点的最小误差值。该值也被称为机器极小值(epsilon)或最小单元取整数,是计算中所能接受的最小的差别值。
$a 和 $b 在小数点后五位精度内都是相等的。
<?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 。详见字符串类型详解。
Note: string 最大可以达到 2GB。
语法
一个字符串可以用 4 种方式表达:
- 单引号
- 双引号
- heredoc 语法结构
- nowdoc 语法结构(自 PHP 5.3.0 起)
单引号
定义一个字符串的最简单的方法是用单引号把它包围起来(字符 '
)。
要表达一个单引号自身,需在它的前面加个反斜线(\
)来转义。要表达一个反斜线自身,则用两个反斜线(\\
)。其它任何方式的反斜线都会被当成反斜线本身:也就是说如果想使用其它转义序列例如 \r
或者 \n
,并不代表任何特殊含义,就单纯是这两个字符本身。
双引号
如果字符串是包围在双引号(")中, PHP 将对一些特殊的字符进行解析:
转义字符
序列 含义
\n 换行(ASCII 字符集中的 LF 或 0x0A (10))
\r 回车(ASCII 字符集中的 CR 或 0x0D (13))
\t 水平制表符(ASCII 字符集中的 HT 或 0x09 (9))
\v 垂直制表符(ASCII 字符集中的 VT 或 0x0B (11))(自 PHP 5.2.5 起)
\e Escape(ASCII 字符集中的 ESC 或 0x1B (27))(自 PHP 5.4.0 起)
\f 换页(ASCII 字符集中的 FF 或 0x0C (12))(自 PHP 5.2.5 起)
\\ 反斜线
\$ 美元标记
\" 双引号
\[0-7]{1,3} 符合该正则表达式序列的是一个以八进制方式来表达的字符
\x[0-9A-Fa-f]{1,2} 符合该正则表达式序列的是一个以十六进制方式来表达的字符
和单引号字符串一样,转义任何其它字符都会导致反斜线被显示出来。PHP 5.1.1 以前,\{$var}
中的反斜线还不会被显示出来。
用双引号定义的字符串最重要的特征是变量会被解析,详见变量解析。
Heredoc结构
Nowdoc 结构
变量解析
当字符串用双引号或 heredoc 结构定义时,其中的变量将会被解析。
这里共有两种语法规则:一种简单规则,一种复杂规则。简单的语法规则是最常用和最方便的,它可以用最少的代码在一个 string 中嵌入一个变量,一个 array 的值,或一个 object 的属性。
复杂规则语法的显著标记是用花括号包围的表达式。
简单语法
当 PHP 解析器遇到一个美元符号($
)时,它会和其它很多解析器一样,去组合尽量多的标识以形成一个合法的变量名。可以用花括号来明确变量名的界线。
<?php
$juice = "apple";
echo "He drank some $juice juice.".PHP_EOL;
// Invalid. "s" is a valid character for a variable name, but the variable is $juice.
echo "He drank some juice made of $juices.";
?>
以上例程会输出:
He drank some apple juice.
He drank some juice made of .
类似的,一个 array 索引或一个 object 属性也可被解析。数组索引要用方括号(]
)来表示索引结束的边际,对象属性则是和上述的变量规则相同。
如果想要表达更复杂的结构,请用复杂语法。
复杂(花括号)语法
复杂语法不是因为其语法复杂而得名,而是因为它可以使用复杂的表达式。
任何具有 string 表达的标量变量,数组单元或对象属性都可使用此语法。只需简单地像在 string 以外的地方那样写出表达式,然后用花括号 {
和 }
把它括起来即可。由于 {
无法被转义,只有 $
紧挨着 {
时才会被识别。可以用 {\$
来表达 {$
。下面的示例可以更好的解释:
<?php
// 显示所有错误
error_reporting(E_ALL);
$great = 'fantastic';
// 无效,输出: This is { fantastic}
echo "This is { $great}";
// 有效,输出: This is fantastic
echo "This is {$great}";
echo "This is ${great}";
// 有效
echo "This square is {$square->width}00 centimeters broad.";
// 有效,只有通过花括号语法才能正确解析带引号的键名
echo "This works: {$arr['key']}";
// 有效
echo "This works: {$arr[4][3]}";
// 这是错误的表达式,因为就象 $foo[bar] 的格式在字符串以外也是错的一样。
// 换句话说,只有在 PHP 能找到常量 foo 的前提下才会正常工作;这里会产生一个
// E_NOTICE (undefined constant) 级别的错误。
echo "This is wrong: {$arr[foo][3]}";
// 有效,当在字符串中使用多重数组时,一定要用括号将它括起来
echo "This works: {$arr['foo'][3]}";
// 有效
echo "This works: " . $arr['foo'][3];
echo "This works too: {$obj->values[3]->name}";
echo "This is the value of the var named $name: {${$name}}";
echo "This is the value of the var named by the return value of getName(): {${getName()}}";
echo "This is the value of the var named by the return value of \$object->getName(): {${$object->getName()}}";
// 无效,输出: This is the return value of getName(): {getName()}
echo "This is the return value of getName(): {getName()}";
?>
也可以在字符串中用此语法通过变量来调用类的属性。
<?php
class foo {
var $bar = 'I am bar.';
}
$foo = new foo();
$bar = 'bar';
$baz = array('foo', 'bar', 'baz', 'quux');
echo "{$foo->$bar}\n";
echo "{$foo->{$baz[1]}}\n";
?>
以上例程会输出:
I am bar.
I am bar.
Note:
函数、方法、静态类变量和类常量只有在 PHP 5 以后才可在
{$}
中使用。然而,只有在该字符串被定义的命名空间中才可以将其值作为变量名来访问。只单一使用花括号 ({}
) 无法处理从函数或方法的返回值或者类常量以及类静态变量的值。
存取和修改字符串中的字符
string 中的字符可以通过一个从 0 开始的下标,用类似 array 结构中的方括号包含对应的数字来访问和修改,比如 $str[42]。可以把 string 当成字符组成的 array。函数 substr() 和 substr_replace() 可用于操作多于一个字符的情况。
Note: string 也可用花括号访问,比如 $str{42}。
Warning
用超出字符串长度的下标写入将会拉长该字符串并以空格填充。非整数类型下标会被转换成整数。非法下标类型会产生一个
E_NOTICE
级别错误。用负数下标写入字符串时会产生一个E_NOTICE
级别错误,用负数下标读取字符串时返回空字符串。写入时只用到了赋值字符串的第一个字符。用空字符串赋值则赋给的值是 NULL 字符。Warning
PHP 的字符串在内部是字节组成的数组。因此用花括号访问或修改字符串对多字节字符集很不安全。仅应对单字节编码例如 ISO-8859-1 的字符串进行此类操作。
自 PHP 5.4 起字符串下标必须为整数或可转换为整数的字符串,否则会发出警告。之前类似 "foo"
的下标会无声地转换成 0
。
Note:
用
[]
或{}
访问任何其它类型(不包括数组或具有相应接口的对象实现)的变量只会无声地返回NULL
。Note:
PHP 5.5 增加了直接在字符串原型中用
[]
或{}
访问字符的支持。
有用的函数和运算符
字符串可以用 ‘.’(点)运算符连接起来,注意 ‘+’(加号)运算符没有这个功能。更多信息参考字符串运算符。
对于 string 的操作有很多有用的函数。
可以参考字符串函数了解大部分函数,高级的查找与替换功能可以参考正则表达式函数或 Perl 兼容正则表达式函数。
另外还有 URL 字符串函数,也有加密/解密字符串的函数(mcrypt 和 mhash)。
最后,可以参考字符类型函数。
转换成字符串
一个值可以通过在其前面加上 (string)
或用 strval() 函数来转变成字符串。在一个需要字符串的表达式中,会自动转换为 string。比如在使用函数 echo 或 print 时,或在一个变量和一个 string 进行比较时,就会发生这种转换。类型和类型转换可以更好的解释下面的事情,也可参考函数 settype()。
一个布尔值 boolean 的 TRUE
被转换成 string 的 "1"
。Boolean 的 FALSE
被转换成 ""
(空字符串)。这种转换可以在 boolean 和 string 之间相互进行。
一个整数 integer 或浮点数 float 被转换为数字的字面样式的 string(包括 float 中的指数部分)。使用指数计数法的浮点数(4.1E+6
)也可转换。
数组 array 总是转换成字符串 "Array"
,因此,echo 和 print 无法显示出该数组的内容。要显示某个单元,可以用 echo $arr['foo']
这种结构。要显示整个数组内容见下文。
NULL
总是被转变成空字符串。
大部分的 PHP 值可以转变成 string 来永久保存,这被称作串行化,可以用函数 serialize() 来实现。如果 PHP 引擎设定支持 WDDX,PHP 值也可被串行化为格式良好的 XML 文本。
字符串转换为数值
当一个字符串被当作一个数值来取值,其结果和类型如下:
如果该字符串没有包含 ‘.’,‘e’ 或 ‘E’ 并且其数字值在整型的范围之内(由 PHP_INT_MAX
所定义),该字符串将被当成 integer 来取值。其它所有情况下都被作为 float 来取值。
该字符串的开始部分决定了它的值。如果该字符串以合法的数值开始,则使用该数值。否则其值为 0(零)。合法数值由可选的正负号,后面跟着一个或多个数字(可能有小数点),再跟着可选的指数部分。指数部分由 ‘e’ 或 ‘E’ 后面跟着一个或多个数字构成。
<?php
$foo = 1 + "10.5"; // $foo is float (11.5)
$foo = 1 + "-1.3e3"; // $foo is float (-1299)
$foo = 1 + "bob-1.3e3"; // $foo is integer (1)
$foo = 1 + "bob3"; // $foo is integer (1)
$foo = 1 + "10 Small Pigs"; // $foo is integer (11)
$foo = 4 + "10.2 Little Piggies"; // $foo is float (14.2)
$foo = "10.0 pigs " + 1; // $foo is float (11)
$foo = "10.0 pigs " + 1.0; // $foo is float (11)
?>
字符串类型详解
PHP 中的 string 的实现方式是一个由字节组成的数组再加上一个整数指明缓冲区长度。并无如何将字节转换成字符的信息,由程序员来决定。字符串由什么值来组成并无限制;特别的,其值为 0
(“NUL bytes”)的字节可以处于字符串任何位置(不过有几个函数,在本手册中被称为非“二进制安全”的,也许会把 NUL 字节之后的数据全都忽略)。
字符串类型的此特性解释了为什么 PHP 中没有单独的“byte”类型 - 已经用字符串来代替了。返回非文本值的函数 - 例如从网络套接字读取的任意数据 - 仍会返回字符串。
由于 PHP 并不特别指明字符串的编码,那字符串到底是怎样编码的呢?例如字符串 "á"
到底是等于 "\xE1"
(ISO-8859-1),"\xC3\xA1"
(UTF-8,C form),"\x61\xCC\x81"
(UTF-8,D form)还是任何其它可能的表达呢?答案是字符串会被按照该脚本文件相同的编码方式来编码。因此如果一个脚本的编码是 ISO-8859-1,则其中的字符串也会被编码为 ISO-8859-1,以此类推。不过这并不适用于激活了 Zend Multibyte 时;此时脚本可以是以任何方式编码的(明确指定或被自动检测)然后被转换为某种内部编码,然后字符串将被用此方式编码。注意脚本的编码有一些约束(如果激活了 Zend Multibyte 则是其内部编码)- 这意味着此编码应该是 ASCII 的兼容超集,例如 UTF-8 或 ISO-8859-1。不过要注意,依赖状态的编码其中相同的字节值可以用于首字母和非首字母而转换状态,这可能会造成问题。
Array数组
PHP 中的数组实际上是一个有序映射。映射是一种把 values 关联到 keys 的类型。此类型在很多方面做了优化,因此可以把它当成真正的数组,或列表(向量),散列表(是映射的一种实现),字典,集合,栈,队列以及更多可能性。由于数组元素的值也可以是另一个数组,树形结构和多维数组也是允许的。
语法
定义数组array()
可以用 array() 语言结构来新建一个数组。它接受任意数量用逗号分隔的 键(key) => 值(value)
对。
array( key => value
, ...
)
// 键(key)可是是一个整数 integer 或字符串 string
// 值(value)可以是任意类型的值
最后一个数组单元之后的逗号可以省略。通常用于单行数组定义中,例如常用 array(1, 2)
而不是 array(1, 2, )
。对多行数组定义通常保留最后一个逗号,这样要添加一个新单元时更方便。
自 5.4 起可以使用短数组定义语法,用 []
替代 array()
。
<?php
$array = array(
"foo" => "bar",
"bar" => "foo",
);
// 自 PHP 5.4 起
$array = [
"foo" => "bar",
"bar" => "foo",
];
?>
key 可以是 integer 或者 string。value 可以是任意类型。
此外 key 会有如下的强制转换:
包含有合法整型值的字符串会被转换为整型。例如键名 “8” 实际会被储存为 8。但是 “08” 则不会强制转换,因为其不是一个合法的十进制数值。
浮点数也会被转换为整型,意味着其小数部分会被舍去。例如键名 8.7 实际会被储存为 8。
布尔值也会被转换成整型。即键名 true 实际会被储存为 1 而键名 false 会被储存为 0。
Null 会被转换为空字符串,即键名 null 实际会被储存为 “”。
数组和对象不能被用为键名。坚持这么做会导致警告:Illegal offset type。
如果在数组定义中多个单元都使用了同一个键名,则只使用了最后一个,之前的都被覆盖了。
Example #2 类型强制与覆盖示例
<?php
$array = array(
1 => "a",
"1" => "b",
1.5 => "c",
true => "d",
);
var_dump($array);
?>
输出:
array(1) {
[1]=>
string(1) "d"
}
上例中所有的键名都被强制转换为 1
,则每一个新单元都会覆盖前一个的值,最后剩下的只有一个 "d"
。
PHP 数组可以同时含有 integer 和 string 类型的键名,因为 PHP 实际并不区分索引数组和关联数组。
PHP 数组可以同时含有 integer 和 string 类型的键名,因为 PHP 实际并不区分索引数组和关联数组。
如果对给出的值没有指定键名,则取当前最大的整数索引值,而新的键名将是该值加一。如果指定的键名已经有了值,则该值会被覆盖。
用方括号语法访问数组单元
数组单元可以通过 array[key]
语法来访问。
Example #6 访问数组单元
<?php
$array = array(
"foo" => "bar",
42 => 24,
"multi" => array(
"dimensional" => array(
"array" => "foo"
)
)
);
var_dump($array["foo"]);
var_dump($array[42]);
var_dump($array["multi"]["dimensional"]["array"]);
?>
输出:
string(3) "bar"
int(24)
string(3) "foo"
Note:
方括号和花括号可以互换使用来访问数组单元(例如 $array[42] 和 $array{42} 在上例中效果相同)。
自 PHP 5.4 起可以用直接对函数或方法调用的结果进行数组解引用,在此之前只能通过一个临时变量。
自 PHP 5.5 起可以直接对一个数组原型进行数组解引用。
Example #7 数组解引用
<?php
function getArray() {
return array(1, 2, 3);
}
// on PHP 5.4
$secondElement = getArray()[1];
// previously
$tmp = getArray();
$secondElement = $tmp[1];
// or
list(, $secondElement) = getArray();
?>
用方括号的语法新建/修改
可以通过明示地设定其中的值来修改一个已有数组。
这是通过在方括号内指定键名来给数组赋值实现的。也可以省略键名,在这种情况下给变量名加上一对空的方括号([]
)。
$arr[key] = value;
$arr[] = value;
// key 可以是 integer 或 string
// value 可以是任意类型的值
如果 $arr 还不存在,将会新建一个,这也是另一种新建数组的方法。不过并不鼓励这样做,因为如果 $arr 已经包含有值(例如来自请求变量的 string)则此值会保留而 []
实际上代表着字符串访问运算符。初始化变量的最好方式是直接给其赋值。
要修改某个值,通过其键名给该单元赋一个新值。要删除某键值对,对其调用 unset() 函数。
<?php
$arr = array(5 => 1, 12 => 2);
$arr[] = 56; // This is the same as $arr[13] = 56;
// at this point of the script
$arr["x"] = 42; // This adds a new element to
// the array with key "x"
unset($arr[5]); // This removes the element from the array
unset($arr); // This deletes the whole array
?>
Note:
如上所述,如果给出方括号但没有指定键名,则取当前最大整数索引值,新的键名将是该值加上 1(但是最小为 0)。如果当前还没有整数索引,则键名将为
0
。注意这里所使用的最大整数键名不一定当前就在数组中。它只要在上次数组重新生成索引后曾经存在过就行了。以下面的例子来说明:
<?php // 创建一个简单的数组 $array = array(1, 2, 3, 4, 5); print_r($array); // 现在删除其中的所有元素,但保持数组本身不变: foreach ($array as $i => $value) { unset($array[$i]); } print_r($array); // 添加一个单元(注意新的键名是 5,而不是你可能以为的 0) $array[] = 6; print_r($array); // 重新索引: $array = array_values($array); $array[] = 7; print_r($array); ?>
输出:
Array ( [0] => 1 [1] => 2 [2] => 3 [3] => 4 [4] => 5 ) Array ( ) Array ( [5] => 6 ) Array ( [0] => 6 [1] => 7 )
实用函数
有很多操作数组的函数,参见数组函数一节。
Note:
unset() 函数允许删除数组中的某个键。但要注意数组将不会重建索引。如果需要删除后重建索引,可以用 array_values() 函数。
<?php $a = array(1 => 'one', 2 => 'two', 3 => 'three'); unset($a[2]); /* will produce an array that would have been defined as $a = array(1 => 'one', 3 => 'three'); and NOT $a = array(1 => 'one', 2 =>'three'); */ $b = array_values($a); // Now $b is array(0 => 'one', 1 =>'three') ?>
foreach 控制结构是专门用于数组的。它提供了一个简单的方法来遍历数组。
数组做什么和不做什么
为什么 $foo[bar]
错了?
因为bar是变量而不是字符串。
应该始终在用字符串表示的数组索引上加上引号。例如用 $foo['bar']
而不是 $foo[bar]
。
Iterables
译:Iterable 是 PHP 7.1中引入的伪类型。它接受任何实现可遍历接口的数组或对象。这两种类型都可以使用 foreach 进行迭代,并且可以在生成器内使用 yield。
Object对象
对象初始化
要创建一个新的对象object,使用new语句实例化一个类:
<?php
class foo
{
function do_foo()
{
echo "Doing foo.";
}
}
$bar = new foo;
$bar->do_foo();
?>
转换为对象
如果将一个对象转换成对象,它将不会有任何变化。如果其它任何类型的值被转换成对象,将会创建一个内置类stdClass的实例。如果该值为 NULL
,则新的实例为空。array转换成object将使键名成为属性名并具有相对应的值。注意:在这个例子里,使用PHP 7.2.0之前的版本,数字键只能通过迭代访问。
<?php
$obj = (object) array('1' => 'foo');
var_dump(isset($obj->{'1'})); // PHP 7.2.0 后输出 'bool(true)',之前版本会输出 'bool(false)'
var_dump(key($obj)); // PHP 7.2.0 后输出 'string(1) "1"',之前版本输出 'int(1)'
?>
对于其他值,会包含进成员变量名 scalar
。
<?php
$obj = (object) 'ciao';
echo $obj->scalar; // outputs 'ciao'
?>
Resource 资源类型
资源 resource 是一种特殊变量,保存了到外部资源的一个引用。资源是通过专门的函数来建立和使用的。所有这些函数及其相应资源类型见附录。
转换为资源
由于资源类型变量保存有为打开文件、数据库连接、图形画布区域等的特殊句柄,因此将其它类型的值转换为资源没有意义。
释放资源
引用计数系统是 Zend 引擎的一部分,可以自动检测到一个资源不再被引用了(和 Java 一样)。这种情况下此资源使用的所有外部资源都会被垃圾回收系统释放。因此,很少需要手工释放内存。
Note: 持久数据库连接比较特殊,它们不会被垃圾回收系统销毁。参见数据库永久连接一章。
NULL
特殊的 NULL
值表示一个变量没有值。NULL 类型唯一可能的值就是 NULL
。
在下列情况下一个变量被认为是 NULL
:
- 被赋值为
NULL
。 - 尚未被赋值。
- 被 unset()。
语法
NULL
类型只有一个值,就是不区分大小写的常量 NULL
。
<?php
$var = NULL;
?>
转换到 NULL
Warning
本特性已自 PHP 7.2.0 起废弃。强烈建议不要使用本特性。
使用 (unset) $var
将一个变量转换为 null 将不会删除该变量或 unset 其值。仅是返回 NULL
值而已。
。。。
变量
基础
PHP 中的变量用一个美元符号后面跟变量名来表示。变量名是区分大小写的。
变量名与 PHP 中其它的标签一样遵循相同的规则。一个有效的变量名由字母或者下划线开头,后面跟上任意数量的字母,数字,或者下划线。按照正常的正则表达式,它将被表述为:’[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*
’。
Note: 在此所说的字母是 a-z,A-Z,以及 ASCII 字符从 127 到 255(
0x7f-0xff
)。
Note:
$this
是一个特殊的变量,它不能被赋值。
Tip
请参见用户空间命名指南。
有关变量的函数信息见变量函数。
<?php
$var = 'Bob';
$Var = 'Joe';
echo "$var, $Var"; // 输出 "Bob, Joe"
$4site = 'not yet'; // 非法变量名;以数字开头
$_4site = 'not yet'; // 合法变量名;以下划线开头
$i站点is = 'mansikka'; // 合法变量名;可以用中文
?>
GB_2312 字符集是目前最常用的汉字编码标准。在这个标准中,每个汉字用2个高位为1的ASCII码表示它的内码,每个字节的ascii码为 161-254 (16 进制A1 - FE),第一个字节 对应于 区码的1-94 区,第二个字节 对应于位码的1-94 位。
变量默认总是传值赋值。那也就是说,当将一个表达式的值赋予一个变量时,整个原始表达式的值被赋值到目标变量。这意味着,例如,当一个变量的值赋予另外一个变量时,改变其中一个变量的值,将不会影响到另外一个变量。有关这种类型的赋值操作,请参阅表达式一章。
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 中)默认值是空字符串以及数组变量的默认值是空数组。
<?php
// Unset AND unreferenced (no use context) variable; outputs NULL
var_dump($unset_var);
// Boolean usage; outputs 'false' (See ternary operators for more on this syntax)
echo($unset_bool ? "true\n" : "false\n");
// String usage; outputs 'string(3) "abc"'
$unset_str .= 'abc';
var_dump($unset_str);
// Integer usage; outputs 'int(25)'
$unset_int += 25; // 0 + 25 => 25
var_dump($unset_int);
// Float/double usage; outputs 'float(1.25)'
$unset_float += 1.25;
var_dump($unset_float);
// Array usage; outputs array(1) { [3]=> string(3) "def" }
$unset_arr[3] = "def"; // array() + array(3 => "def") => array(3 => "def")
var_dump($unset_arr);
// Object usage; creates new stdClass object (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);
?>
依赖未初始化变量的默认值在某些情况下会有问题,例如把一个文件包含到另一个之中时碰上相同的变量名。另外把 register_globals 打开是一个主要的安全隐患。使用未初始化的变量会发出 E_NOTICE 错误,但是在向一个未初始化的数组附加单元时不会。isset() 语言结构可以用来检测一个变量是否已被初始化。
预定义变量
PHP 提供了大量的预定义变量。由于许多变量依赖于运行的服务器的版本和设置,及其它因素,所以并没有详细的说明文档。一些预定义变量在 PHP 以命令行形式运行时并不生效。有关这些变量的详细列表,请参阅预定义变量一章。
Warning
PHP 4.2.0 以及后续版本中,PHP 指令 register_globals 的默认值为 off。这是 PHP 的一个主要变化。让 register_globals 的值为 off 将影响到预定义变量集在全局范围内的有效性。例如,为了得到 DOCUMENT_ROOT 的值,将必须使用 [$_SERVER’DOCUMENT_ROOT’] 代替 D O C U M E N T R O O T , 又 如 , 使 用 [ DOCUMENT_ROOT,又如,使用 [ DOCUMENTROOT,又如,使用[_GET’id’] 来代替 i d 从 U R L ‘ h t t p : / / w w w . e x a m p l e . c o m / t e s t . p h p ? i d = 3 ‘ 中 获 取 i d 值 , 亦 或 使 用 [ id 从 URL `http://www.example.com/test.php?id=3` 中获取 id 值,亦或使用 [ id从URL‘http://www.example.com/test.php?id=3‘中获取id值,亦或使用[_ENV’HOME’] 来代替 $HOME 获取环境变量 HOME 的值。
更多相关信息,请阅读 register_globals 的配置项条目,安全一章中的使用 Register Globals,以及 PHP » 4.1.0 和 » 4.2.0 的发布公告。
如果有可用的 PHP 预定义变量那最好用,如超全局数组。
从 PHP 4.1.0 开始,PHP 提供了一套附加的预定数组,这些数组变量包含了来自 web 服务器(如果可用),运行环境,和用户输入的数据。这些数组非常特别,它们在全局范围内自动生效,例如,在任何范围内自动生效。因此通常被称为自动全局变量(autoglobals)或者超全局变量(superglobals)。(PHP 中没有用户自定义超全局变量的机制。)超全局变量罗列于下文中;但是为了得到它们的内容和关于 PHP 预定义变量的进一步的讨论以及它们的本质,请参阅预定义变量。而且,你也将注意到旧的预定义数组($HTTP_*_VARS)仍旧存在。自 PHP 5.0.0 起, 用 register_long_arrays 设置选项可禁用 长类型的 PHP 预定义变量数组。
Note: 可变变量
超级全局变量不能被用作函数或类方法中的可变变量。
Note:
尽管超全局变量和 HTTP_*_VARS 同时存在,但是它们并不是同一个变量,所以改变其中一个的值并不会对另一个产生影响。
如果某些 variables_order 中的变量没有设定,它们的对应的 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
的例子:
Example #1 使用 global
<?php
$a = 1;
$b = 2;
function Sum()
{
global $a, $b;
$b = $a + $b;
}
Sum();
echo $b;
?>
以上脚本的输出将是“3”。在函数中声明了全局变量 $a 和 $b 之后,对任一变量的所有引用都会指向其全局版本。对于一个函数能够声明的全局变量的最大个数,PHP 没有限制。
在全局范围内访问变量的第二个办法,是用特殊的 PHP 自定义 $GLOBALS 数组。前面的例子可以写成:
Example #2 使用 $GLOBALS 替代 global
<?php
$a = 1;
$b = 2;
function Sum()
{
$GLOBALS['b'] = $GLOBALS['a'] + $GLOBALS['b'];
}
Sum();
echo $b;
?>
G L O B A L S ] ( h t t p s : / / w w w . p h p . n e t / m a n u a l / z h / r e s e r v e d . v a r i a b l e s . g l o b a l s . p h p ) 是 一 个 关 联 数 组 , 每 一 个 变 量 为 一 个 元 素 , 键 名 对 应 变 量 名 , 值 对 应 变 量 的 内 容 。 [ GLOBALS](https://www.php.net/manual/zh/reserved.variables.globals.php) 是一个关联数组,每一个变量为一个元素,键名对应变量名,值对应变量的内容。[ GLOBALS](https://www.php.net/manual/zh/reserved.variables.globals.php)是一个关联数组,每一个变量为一个元素,键名对应变量名,值对应变量的内容。[GLOBALS 之所以在全局范围内存在,是因为 $GLOBALS 是一个超全局变量。以下范例显示了超全局变量的用处:
Example #3 演示超全局变量和作用域的例子
<?php
function test_global()
{
// 大多数的预定义变量并不 "super",它们需要用 'global' 关键字来使它们在函数的本地区域中有效。
global $HTTP_POST_VARS;
echo $HTTP_POST_VARS['name'];
// Superglobals 在任何范围内都有效,它们并不需要 'global' 声明。Superglobals 是在 PHP 4.1.0 引入的。
echo $_POST['name'];
}
?>
使用静态变量
变量范围的另一个重要特性是静态变量(static variable)。静态变量仅在局部函数域中存在,但当程序执行离开此作用域时,其值并不丢失。看看下面的例子:
Example #4 演示需要静态变量的例子
<?php
function Test()
{
$a = 0;
echo $a;
$a++;
}
?>
现在,变量 $a 仅在第一次调用 test() 函数时被初始化,之后每次调用 test() 函数都会输出 $a 的值并加一。
静态变量也提供了一种处理递归函数的方法。递归函数是一种调用自己的函数。写递归函数时要小心,因为可能会无穷递归下去。必须确保有充分的方法来中止递归。以下这个简单的函数递归计数到 10,使用静态变量 $count 来判断何时停止:
Example #6 静态变量与递归函数
<?php
function test()
{
static $count = 0;
$count++;
echo $count;
if ($count < 10) {
test();
}
$count--;
}
?>
Note:
静态变量可以按照上面的例子声明。如果在声明中用表达式的结果对其赋值会导致解析错误。
Example #7 声明静态变量
<?php function foo(){ static $int = 0; // correct static $int = 1+2; // wrong (as it is an expression) static $int = sqrt(121); // wrong (as it is an expression too) $int++; echo $int; } ?>
php7以上可以解析第2个int,第三个int都不行。
静态声明是在编译时解析的。
Note:
在函数之外使用
global
关键字不算错。可以用于在一个函数之内包含文件时。
全局和静态变量的引用
略
可变变量
有时候使用可变变量名是很方便的。就是说,一个变量的变量名可以动态的设置和使用。一个普通的变量通过声明来设置,例如:
<?php
$a = 'hello';
$$a = 'world'; //==> $$a = $hello;
echo $hello;
?>
一个可变变量获取了一个普通变量的值作为这个可变变量的变量名。在上面的例子中 hello 使用了两个美元符号($)以后,就可以作为一个可变变量的变量了。
这时,两个变量都被定义了:$a 的内容是“hello”并且 $hello 的内容是“world”。
要将可变变量用于数组,必须解决一个模棱两可的问题。这就是当写下 KaTeX parse error: Can't use function '$' in math mode at position 19: …] 时,解析器需要知道是想要 $̲a[1] 作为一个变量呢,还是…a 作为一个变量并取出该变量中索引为 [1] 的值。解决此问题的语法是,对第一种情况用 KaTeX parse error: Expected '}', got 'EOF' at end of input: {a[1]},对第二种情况用 KaTeX parse error: Expected '}', got 'EOF' at end of input: {a}[1]。
类的属性也可以通过可变属性名来访问。可变属性名将在该调用所处的范围内被解析。例如,对于 f o o − > foo-> foo−>bar 表达式,则会在本地范围来解析 $bar 并且其值将被用于 $foo 的属性名。对于 $bar 是数组单元时也是一样。
Example #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";//$foo->$bar
echo $foo->$baz[1] . "\n";//$foo->${baz[1]}
$start = 'b';
$end = 'ar';
echo $foo->{$start . $end} . "\n";
$arr = 'arr';
echo $foo->$arr[1] . "\n";//$foo->${arr[1]}
echo $foo->{$arr}[1] . "\n";//$foo->{$arr}[1]
?>
输出:
I am bar.
I am bar.
I am bar.
I am r.
I am B.
Warning
注意,在 PHP 的函数和类的方法中,超全局变量不能用作可变变量。
$this
变量也是一个特殊变量,不能被动态引用。
来自PHP之外的变量
$_GET,$_POST
Note:
超全局数组例如 P O S T ] ( h t t p s : / / w w w . p h p . n e t / m a n u a l / z h / r e s e r v e d . v a r i a b l e s . p o s t . p h p ) 和 [ _POST](https://www.php.net/manual/zh/reserved.variables.post.php) 和 [ POST](https://www.php.net/manual/zh/reserved.variables.post.php)和[_GET,自 PHP 4.1.0 起可用。
Note:
变量名中的点和空格被转换成下划线。例如
<input name="a.b" />
变成了$_REQUEST["a_b"]
。
如上所示,在 PHP 4.2.0 之前 register_globals 的默认值是 on。PHP 社区鼓励大家不要依赖此指令,建议在编码时假定其为 off。
Note:
magic_quotes_gpc 配置指令影响到 Get,Post 和 Cookie 的值。如果打开,值 (It’s “PHP!”) 会自动转换成 (It’s “PHP!”)。十多年前对数据库的插入需要如此转义,如今已经过时了,应该关闭。参见 addslashes(),stripslashes() 和 magic_quotes_sybase。
IMAGE SUBMIT 变量名
HTTP Cookies
变量名中的点
确定变量类型