PHP学习笔记(一)
语言参考
一、基本语法
(一)PHP 标记
当解析一个文件时,PHP 会寻找起始和结束标记,也就是 <?php 和 ?>,这告诉 PHP 开始和停止解析二者之间的代码。此种解析方式使得 PHP 可以被嵌入到各种不同的文档中去,而任何起始和结束标记之外的部分都会被 PHP 解析器忽略。
PHP 也允许使用短标记 <? 和 ?>,但不鼓励使用。只有通过激活 php.ini 中的 short_open_tag 配置指令或者在编译 PHP 时使用了配置选项 --enable-short-tags 时才能使用短标记。
如果文件内容是纯 PHP 代码,最好在文件末尾删除 PHP 结束标记。这可以避免在 PHP 结束标记之后万一意外加入了空格或者换行符,会导致 PHP 开始输出这些空白,而脚本中此时并无输出的意图。
(二)从 HTML 中分离
凡是在一对开始和结束标记之外的内容都会被 PHP 解析器忽略,这使得 PHP 文件可以具备混合内容。
-
Note: 此外注意如果将 PHP 嵌入到 XML 或 XHTML 中则需要使用 <?php ?> 标记以保持符合标准。
-
Note: 在以下情况应避免使用短标记:开发需要再次发布的程序或者库,或者在用户不能控制的服务器上开发。因为目标服务器可能不支持短标记。为了代码的移植及发行,确保不要使用短标记。
-
Note: 在 PHP 5.2 和之前的版本中,解释器不允许一个文件的全部内容就是一个开始标记 <?php。自 PHP 5.3 起则允许此种文件,但要开始标记后有一个或更多白空格符。
-
Note: 自 PHP 5.4 起,短格式的 echo 标记 <?= 总会被识别并且合法,而不管 short_open_tag 的设置是什么。
(三)指令分隔符
同 C 或 Perl 一样,PHP 需要在每个语句后用分号结束指令。一段 PHP 代码中的结束标记隐含表示了一个分号;在一个 PHP 代码段中的最后一行可以不用分号结束。如果后面还有新行,则代码段的结束标记包含了行结束。
- Note: 文件末尾的 PHP 代码段结束标记可以不要,有些情况下当使用 include 或者 require 时省略掉会更好些,这样不期望的空白符就不会出现在文件末尾,之后仍然可以输出响应标头。在使用输出缓冲时也很便利,就不会看到由包含文件生成的不期望的空白符。
(四)注释
单行注释仅仅注释到行末或者当前的 PHP 代码块,视乎哪个首先出现。这意味着在 // ... ?> 或者 # ... ?> 之后的 HTML 代码将被显示出来:?> 跳出了 PHP 模式并返回了 HTML 模式,// 或 # 并不能影响到这一点。如果启用了 asp_tags 配置选项,其行为和 // %> 或 # %> 相同。不过, 标记在单行注释中不会跳出 PHP 模式。
C 风格的注释在碰到第一个 */
时结束。要确保不要嵌套 C 风格的注释。试图注释掉一大块代码时很容易出现该错误。
二、类型
(一)简介
PHP 支持 8 种原始数据类型。
- 四种标量类型:
- boolean (布尔型)
- integer (整型)
- float (浮点型,也称作 double )
- string (字符串)
- 两种复合类型:
- array (数组)
- object (对象)
- 最后是两种特殊类型:
- resource (资源)
- NULL (无类型)
- 为了确保代码的易读性,本手册还介绍了一些伪类型:
- mixed (混合类型)
- number (数字类型)
- callback (回调类型)
以及伪变量 $...。
可能还会读到一些关于“双精度(double)”类型的参考。实际上 double 和 float 是相同的,由于一些历史的原因,这两个名称同时存在。
变量的类型通常不是由程序员设定的,确切地说,是由 PHP 根据该变量使用的上下文在运行时决定的。
- Note: 如果想查看某个表达式的值和类型,用 var_dump() 函数。
如果只是想得到一个易读懂的类型的表达方式用于调试,用 gettype() 函数。要查看某个类型,不要用 gettype() ,而用 is_type 函数。
如果要将一个变量强制转换为某类型,可以对其使用强制转换或者 settype() 函数。
注意变量根据其当时的类型在特定场合下会表现出不同的值。更多信息见类型转换的判别。此外,还可以参考 PHP 类型比较表看不同类型相互比较的例子。
(二)Boolean 布尔类型
这是最简单的类型。 boolean 表达了真值,可以为 TRUE 或 FALSE 。
语法
要指定一个布尔值,使用关键字 TRUE 或 FALSE 。两个都不区分大小写。
通常运算符所返回的 boolean 值结果会被传递给控制流程。
转换为布尔值
要明确地将一个值转换成 boolean ,用 (bool) 或者 (boolean) 来强制转换。但是很多情况下不需要用强制转换,因为当运算符,函数或者流程控制结构需要一个 boolean 参数时,该值会被自动转换。
参见类型转换的判别。
当转换为 boolean 时,以下值被认为是 FALSE :
- 布尔值 FALSE 本身
- 整型值 0(零)
- 浮点型值 0.0(零)
- 空字符串,以及字符串 "0"
- 不包括任何元素的数组
- 不包括任何成员变量的对象(仅 PHP 4.0 适用)
- 特殊类型 NULL(包括尚未赋值的变量)
- 从空标记生成的 SimpleXML 对象
所有其它值都被认为是 TRUE (包括任何资源)。
- Note: -1 和其它非零值(不论正负)一样,被认为是 TRUE !
<?php
var_dump ((bool) "" ); // bool(false)
echo '<br />';
var_dump ((bool) 1 ); // bool(true)
echo '<br />';
var_dump ((bool) - 2 ); // bool(true)
echo '<br />';
var_dump ((bool) "foo" ); // bool(true)
echo '<br />';
var_dump ((bool) 2.3e5 ); // bool(true)
echo '<br />';
var_dump ((bool) array( 12 )); // bool(true)
echo '<br />';
var_dump ((bool) array()); // bool(false)
echo '<br />';
var_dump ((bool) "false" ); // bool(true)
echo '<br />';
var_dump ((bool) 0 ); // bool(false)
?>
(三)Integer 整型
一个 integer 是集合 ? = {..., -2, -1, 0, 1, 2, ...} 中的一个数。
参见:
- 任意长度整数/GMP
- 浮点型
- 任意精度数学库/BCMath
语法
整型值可以使用十进制,十六进制,八进制或二进制表示,前面可以加上可选的符号(- 或者 +)。
二进制表达的 integer 自 PHP 5.4.0 起可用。
要使用八进制表达,数字前必须加上 0(零)。要使用十六进制表达,数字前必须加上 0x。要使用二进制表达,数字前必须加上 0b。
整型数的字长和平台有关,尽管通常最大值是大约二十亿(32 位有符号)。64 位平台下的最大值通常是大约 9E18。PHP 不支持无符号整数。 Integer 值的字长可以用常量 PHP_INT_SIZE 来表示,自 PHP 4.4.0 和 PHP 5.0.5后,最大值可以用常量 PHP_INT_MAX 来表示。
-
Warning:如果向八进制数传递了一个非法数字(即 8 或 9),则后面其余数字会被忽略。
-
整数溢出:如果给定的一个数超出了 integer 的范围,将会被解释为 float 。同样如果执行的运算结果超出了 integer 范围,也会返回 float 。
Example #3 32 位系统下的整数溢出
<?php
$large_number = 2147483647 ;
var_dump ( $large_number ); // int(2147483647)
$large_number = 2147483648 ;
var_dump ( $large_number ); // float(2147483648)
$million = 1000000 ;
$large_number = 50000 * $million ;
var_dump ( $large_number ); // float(50000000000)
?>
Example #4 64 位系统下的整数溢出
<?php
$large_number = 9223372036854775807 ;
var_dump ( $large_number ); // int(9223372036854775807)
$large_number = 9223372036854775808 ;
var_dump ( $large_number ); // float(9.2233720368548E+18)
$million = 1000000 ;
$large_number = 50000000000000 * $million ;
var_dump ( $large_number ); // float(5.0E+19)
?>
PHP 中没有整除的运算符。1/2 产生出 float 0.5。值可以舍弃小数部分强制转换为 integer ,或者使用 round() 函数可以更好地进行四舍五入。
<?php
var_dump ( 25 / 7 ); // float(3.5714285714286)
var_dump ((int) ( 25 / 7 )); // int(3)
var_dump ( round ( 25 / 7 )); // float(4)
?>
- 转换为整型
要明确地将一个值转换为 integer ,用 (int) 或 (integer) 强制转换。不过大多数情况下都不需要强制转换,因为当运算符,函数或流程控制需要一个 integer 参数时,值会自动转换。还可以通过函数 intval() 来将一个值转换成整型。
参见:类型转换的判别。
- 从布尔值转换
FALSE 将产生出 0(零), TRUE 将产生出 1(壹)。
- 从浮点型转换
当从浮点数转换成整数时,将向下取整。
如果浮点数超出了整数范围(32 位平台下通常为 +/- 2.15e+9 = 2^31,64 位平台下通常为 +/- 9.22e+18 = 2^63),则结果为未定义,因为没有足够的精度给出一个确切的整数结果。在此情况下没有警告,甚至没有任何通知!
-
Warning:决不要将未知的分数强制转换为 integer ,这样有时会导致不可预料的结果。
-
从字符串转换:参见字符串转换为数值。
-
从其它类型转换
Caution:没有定义从其它类型转换为整型的行为。不要依赖任何现有的行为,因为它会未加通知地改变。
(四)Float 浮点型
浮点型(也叫浮点数 float,双精度数 double 或实数 real)可以用以下任一语法定义:
<?php
$a = 1.234 ;
$b = 1.2e3 ;
$c = 7E-10 ;
?>
浮点数的字长和平台相关,尽管通常最大值是 1.8e308 并具有 14 位十进制数字的精度(64 位 IEEE 格式)。
浮点数的精度有限。尽管取决于系统,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 所代表的结果。此结果代表着一个在浮点数运算中未定义或不可表述的值。任何拿此值与其它任何值进行的松散或严格比较的结果都是 FALSE 。
由于 NAN 代表着任何不同值,不应拿 NAN 去和其它值进行比较,包括其自身,应该用 is_nan() 来检查。
(五)String 字符串
一个字符串 string 就是由一系列的字符组成,其中每个字符等同于一个字节。这意味着 PHP 只能支持 256 的字符集,因此不支持 Unicode 。详见字符串类型详解。
- Note: string 最大可以达到 2GB。
语法
一个字符串可以用 4 种方式表达:
- 单引号
- 双引号
- heredoc 语法结构
- nowdoc 语法结构(自 PHP 5.3.0 起)
- 单引号
定义一个字符串的最简单的方法是用单引号把它包围起来(字符 ')。
要表达一个单引号自身,需在它的前面加个反斜线(\)来转义。要表达一个反斜线自身,则用两个反斜线(\)。其它任何方式的反斜线都会被当成反斜线本身:也就是说如果想使用其它转义序列例如 \r 或者 \n,并不代表任何特殊含义,就单纯是这两个字符本身。
- Note: 不像双引号和 heredoc 语法结构,在单引号字符串中的变量和特殊字符的转义序列将不会被替换。
<?php
echo 'this is a simple string' ;
// 可以录入多行
echo 'You can also have embedded newlines in
strings this way as it is
okay to do' ;
// 输出: Arnold once said: "I'll be back"
echo 'Arnold once said: "I\'ll be back"' ;
// 输出: You deleted C:\*.*?
echo 'You deleted C:\\*.*?' ;
// 输出: You deleted C:\*.*?
echo 'You deleted C:\*.*?' ;
// 输出: This will not expand: \n a newline
echo 'This will not expand: \n a newline' ;
// 输出: Variables do not $expand $either
echo 'Variables do not $expand $either' ;
?>
- 双引号
如果字符串是包围在双引号(")中, 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 结构
第三种表达字符串的方法是用 heredoc 句法结构:<<<。在该运算符之后要提供一个标识符,然后换行。接下来是字符串 string 本身,最后要用前面定义的标识符作为结束标志。
结束时所引用的标识符必须在该行的第一列,而且,标识符的命名也要像其它标签一样遵守 PHP 的规则:只能包含字母、数字和下划线,并且必须以字母和下划线作为开头。
- Warning
要注意的是结束标识符这行除了可能有一个分号(;)外,绝对不能包含其它字符。这意味着标识符不能缩进,分号的前后也不能有任何空白或制表符。更重要的是结束标识符的前面必须是个被本地操作系统认可的换行,比如在 UNIX 和 Mac OS X 系统中是 \n,而结束定界符(可能其后有个分号)之后也必须紧跟一个换行。
如果不遵守该规则导致结束标识不“干净”,PHP 将认为它不是结束标识符而继续寻找。如果在文件结束前也没有找到一个正确的结束标识符,PHP 将会在最后一行产生一个解析错误。
Heredocs 结构不能用来初始化类的属性。自 PHP 5.3 起,此限制仅对 heredoc 包含变量时有效。
Example #1 非法的示例
<?php
class foo {
public $bar = <<<EOT
bar
EOT;
}
?>
Heredoc 结构就象是没有使用双引号的双引号字符串,这就是说在 heredoc 结构中单引号不用被转义,但是上文中列出的转义序列还可以使用。变量将被替换,但在 heredoc 结构中含有复杂的变量时要格外小心。
Example #2 Heredoc 结构的字符串示例
<?php
$str = <<<EOD
Example of string
spanning multiple lines
using heredoc syntax.
EOD;
/* 含有变量的更复杂示例 */
class foo
{
var $foo ;
var $bar ;
function foo ()
{
$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
也可以把 Heredoc 结构用在函数参数中来传递数据:
Example #3 Heredoc 结构在参数中的示例
<?php
var_dump (array(<<<EOD
foobar!
EOD
));
?>
在 PHP 5.3.0 以后,也可以用 Heredoc 结构来初始化静态变量和类的属性和常量:
Example #4 使用 Heredoc 结构来初始化静态值
<?php
// 静态变量
function foo ()
{
static $bar = <<<LABEL
Nothing in here...
LABEL;
}
// 类的常量、属性
class foo
{
const BAR = <<<FOOBAR
Constant example
FOOBAR;
public $baz = <<<FOOBAR
Property example
FOOBAR;
}
?>
自 PHP 5.3.0 起还可以在 Heredoc 结构中用双引号来声明标识符:
Example #5 在 heredoc 结构中使用双引号
<?php
echo <<<"FOOBAR"
Hello World!
FOOBAR;
?>
- Nowdoc 结构
就象 heredoc 结构类似于双引号字符串,Nowdoc 结构是类似于单引号字符串的。Nowdoc 结构很象 heredoc 结构,但是 nowdoc 中不进行解析操作。这种结构很适合用于嵌入 PHP 代码或其它大段文本而无需对其中的特殊字符进行转义。与 SGML 的 <![CDATA[ ]]> 结构是用来声明大段的不用解析的文本类似,nowdoc 结构也有相同的特征。
一个 nowdoc 结构也用和 heredocs 结构一样的标记 <<<, 但是跟在后面的标识符要用单引号括起来,即 <<<'EOT'。Heredoc 结构的所有规则也同样适用于 nowdoc 结构,尤其是结束标识符的规则。
Example #6 Nowdoc 结构字符串示例
<?php
$str = <<<'EOD'
Example of string
spanning multiple lines
using nowdoc syntax.
EOD;
/* 含有变量的更复杂的示例 */
class foo
{
public $foo ;
public $bar ;
function foo ()
{
$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
- Note: 不象 heredoc 结构,nowdoc 结构可以用在任意的静态数据环境中,最典型的示例是用来初始化类的属性或常量:
Example #7 静态数据的示例
<?php
class foo {
public $bar = <<<'EOT'
bar
EOT;
}
?>
-
Note: Nowdoc 结构是在 PHP 5.3.0 中加入的。
-
变量解析
当 字符串 用双引号或 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 属性也可被解析。数组索引要用方括号(])来表示索引结束的边际,对象属性则是和上述的变量规则相同。
Example #8 简单语法示例
<?php
$juices = array( "apple" , "orange" , "koolaid1" => "purple" );
echo "He drank some $juices [ 0 ] juice." . PHP_EOL ;
echo "He drank some $juices [ 1 ] juice." . PHP_EOL ;
echo "He drank some juice made of $juice [ 0 ] s." . PHP_EOL ; // Won't work
echo "He drank some $juices [ koolaid1 ] juice." . PHP_EOL ;
class people {
public $john = "John Smith" ;
public $jane = "Jane Smith" ;
public $robert = "Robert Paulsen" ;
public $smith = "Smith" ;
}
$people = new people ();
echo " $people -> john drank some $juices [ 0 ] juice." . PHP_EOL ;
echo " $people -> john then said hello to $people -> jane ." . PHP_EOL ;
echo " $people -> john 's wife greeted $people -> robert ." . PHP_EOL ;
echo " $people -> robert greeted the two $people -> smiths ." ; // Won't work
?>
以上例程会输出:
He drank some apple juice.
He drank some orange juice.
He drank some juice made of s.
He drank some purple juice.
John Smith drank some apple juice.
John Smith then said hello to Jane Smith.
John Smith's wife greeted Robert Paulsen.
Robert Paulsen greeted the two .
如果想要表达更复杂的结构,请用复杂语法。
- 复杂(花括号)语法
复杂语法不是因为其语法复杂而得名,而是因为它可以使用复杂的表达式。
任何具有 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 以后才可在 {$} 中使用。然而,只有在该字符串被定义的命名空间中才可以将其值作为变量名来访问。只单一使用花括号 ({}) 无法处理从函数或方法的返回值或者类常量以及类静态变量的值。
<?php
// 显示所有错误
error_reporting ( E_ALL );
class beers {
const softdrink = 'rootbeer' ;
public static $ale = 'ipa' ;
}
$rootbeer = 'A & W' ;
$ipa = 'Alexander Keith\'s' ;
// 有效,输出: I'd like an A & W
echo "I'd like an {${ beers :: softdrink }} \n" ;
// 也有效,输出: I'd like an Alexander Keith's
echo "I'd like an {${ beers :: $ale }} \n" ;
?>
- 存取和修改字符串中的字符
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 的字符串进行此类操作。
Example #9 一些字符串示例
<?php
// 取得字符串的第一个字符
$str = 'This is a test.' ;
$first = $str [ 0 ];
// 取得字符串的第三个字符
$third = $str [ 2 ];
// 取得字符串的最后一个字符
$str = 'This is still a test.' ;
$last = $str [ strlen ( $str )- 1 ];
// 修改字符串的最后一个字符
$str = 'Look at the sea' ;
$str [ strlen ( $str )- 1 ] = 'e' ;
?>
自 PHP 5.4 起字符串下标必须为整数或可转换为整数的字符串,否则会发出警告。之前例如 "foo" 的下标会无声地转换成 0。
Example #10 PHP 5.3 和 PHP 5.4 的区别
<?php
$str = 'abc' ;
var_dump ( $str [ '1' ]);
var_dump (isset( $str [ '1' ]));
var_dump ( $str [ '1.0' ]);
var_dump (isset( $str [ '1.0' ]));
var_dump ( $str [ 'x' ]);
var_dump (isset( $str [ 'x' ]));
var_dump ( $str [ '1x' ]);
var_dump (isset( $str [ '1x' ]));
?>
以上例程在PHP 5.3中的输出:
string(1) "b"
bool(true)
string(1) "b"
bool(true)
string(1) "a"
bool(true)
string(1) "b"
bool(true)
以上例程在PHP 5.4中的输出:
string(1) "b"
bool(true)Warning: Illegal string offset '1.0' in /tmp/t.php on line 7
string(1) "b"
bool(false)Warning: Illegal string offset 'x' in /tmp/t.php on line 9
string(1) "a"
bool(false)
string(1) "b"
bool(false)
-
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)也可转换。
- Note: 在脚本的区域(category LC_NUMERIC)中定义了十进制小数点字符。参见 setlocale() 。
数组 array 总是转换成字符串 "Array",因此, echo 和 print 无法显示出该 数组 的内容。要显示某个单元,可以用 echo $arr['foo'] 这种结构。要显示整个数组内容见下文。
在 PHP 4 中对象 object 总是被转换成字符串 "Object",如果为了调试原因需要打印出对象的值,请继续阅读下文。为了得到对象的类的名称,可以用 get_class() 函数。自 PHP 5 起,适当时可以用 __toString 方法。
资源 resource 总会被转变成 "Resource id #1" 这种结构的字符串,其中的 1 是 PHP 在运行时分配给该 resource 的唯一值。不要依赖此结构,可能会有变更。要得到一个 resource 的类型,可以用函数 get_resource_type() 。
NULL 总是被转变成空字符串。
如上面所说的,直接把 array , object 或 resource 转换成 string 不会得到除了其类型之外的任何有用信息。可以使用函数 print_r() 和 var_dump() 列出这些类型的内容。
大部分的 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)
?>
更多信息可以参考 Unix 手册中的 strtod(3)。
本节中的示例可以通过复制/粘贴到下面的代码中来显示:
<?php
echo "\$foo== $foo ; type is " . gettype ( $foo ) . "<br />\n" ;
?>
不要想像在 C 语言中的那样,通过将一个字符转换成整数以得到其代码。使用函数 ord() 和 chr() 实现 ASCII 码和字符间的转换。
- 字符串类型详解
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。不过要注意,依赖状态的编码其中相同的字节值可以用于首字母和非首字母而转换状态,这可能会造成问题。
当然了,要做到有用,操作文本的函数必须假定字符串是如何编码的。不幸的是,PHP 关于此的函数有很多变种:
- 某些函数假定字符串是以单字节编码的,但并不需要将字节解释为特定的字符。例如 substr() , strpos() , strlen() 和 strcmp() 。理解这些函数的另一种方法是它们作用于内存缓冲区,即按照字节和字节下标操作。
- 某些函数被传递入了字符串的编码方式,也可能会假定默认无此信息。例如 htmlentities() 和 mbstring 扩展中的大部分函数。
- 其它函数使用了当前区域(见 setlocale() ),但是逐字节操作。例如 strcasecmp() , strtoupper() 和 ucfirst() 。这意味着这些函数只能用于单字节编码,而且编码要与区域匹配。例如 strtoupper("á") 在区域设定正确并且 á 是单字节编码时会返回 "?"。如果是用 UTF-8 编码则不会返回正确结果,其结果根据当前区域有可能返回损坏的值。
- 最后一些函数会假定字符串是使用某特定编码的,通常是 UTF-8。intl 扩展和 PCRE(上例中仅在使用了 u 修饰符时)扩展中的大部分函数都是这样。尽管这是由于其特殊用途, utf8_decode() 会假定 UTF-8 编码而 utf8_encode() 会假定 ISO-8859-1 编码。
最后,要书写能够正确使用 Unicode 的程序依赖于很小心地避免那些可能会损坏数据的函数。要使用来自于 intl 和 mbstring 扩展的函数。不过使用能处理 Unicode 编码的函数只是个开始。不管用何种语言提供的函数,最基本的还是了解 Unicode 规格。例如一个程序如果假定只有大写和小写,那可是大错特错。
(六)Array 数组
PHP 中的 数组 实际上是一个有序映射。映射是一种把 values 关联到 keys 的类型。此类型在很多方面做了优化,因此可以把它当成真正的数组,或列表(向量),散列表(是映射的一种实现),字典,集合,栈,队列以及更多可能性。由于数组元素的值也可以是另一个数组,树形结构和多维数组也是允许的。
解释这些结构超出了本手册的范围,但对于每种结构至少会提供一个例子。要得到这些结构的更多信息,建议参考有关此广阔主题的其它著作。
语法
定义数组 array()
可以用 array() 语言结构来新建一个数组。它接受任意数量用逗号分隔的 键(key) => 值(value) 对。
array( key => value
, ...
)
// 键(key)可是是一个整数 integer 或字符串 string
// 值(value)可以是任意类型的值
最后一个数组单元之后的逗号可以省略。通常用于单行数组定义中,例如常用 array(1, 2) 而不是 array(1, 2, )。对多行数组定义通常保留最后一个逗号,这样要添加一个新单元时更方便。
自 5.4 起可以使用短数组定义语法,用 [] 替代 array()。
Example #1 一个简单数组
<?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 实际并不区分索引数组和关联数组。
如果对给出的值没有指定键名,则取当前最大的整数索引值,而新的键名将是该值加一。如果指定的键名已经有了值,则该值会被覆盖。
Example #3 混合 integer 和 string 键名
<?php
$array = array(
"foo" => "bar" ,
"bar" => "foo" ,
100 => - 100 ,
- 100 => 100 ,
);
var_dump ( $array );
?>
以上例程会输出:
array(4) {
["foo"]=>
string(3) "bar"
["bar"]=>
string(3) "foo"
[100]=>
int(-100)
[-100]=>
int(100)
}
key 为可选项。如果未指定,PHP 将自动使用之前用过的最大 integer 键名加上 1 作为新的键名。
Example #4 没有键名的索引数组
<?php
$array = array( "foo" , "bar" , "hallo" , "world" );
var_dump ( $array );
?>
以上例程会输出:
array(4) {
[0]=>
string(3) "foo"
[1]=>
string(3) "bar"
[2]=>
string(5) "hallo"
[3]=>
string(5) "world"
}
还可以只对某些单元指定键名而对其它的空置:
Example #5 仅对部分单元指定键名
<?php
$array = array(
"a" ,
"b" ,
6 => "c" ,
"d" ,
);
var_dump ( $array );
?>
以上例程会输出:
array(4) {
[0]=>
string(1) "a"
[1]=>
string(1) "b"
[6]=>
string(1) "c"
[7]=>
string(1) "d"
}
可以看到最后一个值 "d" 被自动赋予了键名 7。这是由于之前最大的整数键名是 6。
- 用方括号语法访问数组单元
数组单元可以通过 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 ();
?>
-
Note: 试图访问一个未定义的数组键名与访问任何未定义变量一样:会导致 E_NOTICE 级别错误信息,其结果为 NULL 。
-
用方括号的语法新建/修改
可以通过明示地设定其中的值来修改一个已有数组。
这是通过在方括号内指定键名来给数组赋值实现的。也可以省略键名,在这种情况下给变量名加上一对空的方括号([])。
$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] 错了?
应该始终在用字符串表示的数组索引上加上引号。例如用 $foo['bar'] 而不是 $foo[bar]。但是为什么呢?可能在老的脚本中见过如下语法:
<?php
$foo [ bar ] = 'enemy' ;
echo $foo [ bar ];
// etc
?>
这样是错的,但可以正常运行。那么为什么错了呢?原因是此代码中有一个未定义的常量(bar)而不是字符串('bar'-注意引号),而 PHP 可能会在以后定义此常量,不幸的是你的代码中有同样的名字。它能运行,是因为 PHP 自动将裸字符串(没有引号的字符串且不对应于任何已知符号)转换成一个其值为该裸字符串的正常字符串。例如,如果没有常量定义为 bar ,PHP 将把它替代为 'bar' 并使用之。
- Note: 这并不意味着总是给键名加上引号。用不着给键名为常量或变量的加上引号,否则会使 PHP 不能解析它们。
<?php
error_reporting ( E_ALL );
ini_set ( 'display_errors' , true );
ini_set ( 'html_errors' , false );
// Simple array:
$array = array( 1 , 2 );
$count = count ( $array );
for ( $i = 0 ; $i < $count ; $i ++) {
echo "\nChecking $i : \n" ;
echo "Bad: " . $array [ '$i' ] . "\n" ;
echo "Good: " . $array [ $i ] . "\n" ;
echo "Bad: { $array [ '$i' ]} \n" ;
echo "Good: { $array [ $i ]} \n" ;
}
?>
以上例程会输出:
Checking 0:
Notice: Undefined index: $i in /path/to/script.html on line 9
Bad:
Good: 1
Notice: Undefined index: $i in /path/to/script.html on line 11
Bad:
Good: 1Checking 1:
Notice: Undefined index: $i in /path/to/script.html on line 9
Bad:
Good: 2
Notice: Undefined index: $i in /path/to/script.html on line 11
Bad:
Good: 2
演示此行为的更多例子:
<?php
// Show all errors
error_reporting ( E_ALL );
$arr = array( 'fruit' => 'apple' , 'veggie' => 'carrot' );
// Correct
print $arr [ 'fruit' ]; // apple
print $arr [ 'veggie' ]; // carrot
// Incorrect. This works but also throws a PHP error of level E_NOTICE because
// of an undefined constant named fruit
//
// Notice: Use of undefined constant fruit - assumed 'fruit' in...
print $arr [ fruit ]; // apple
// This defines a constant to demonstrate what's going on. The value 'veggie'
// is assigned to a constant named fruit.
define ( 'fruit' , 'veggie' );
// Notice the difference now
print $arr [ 'fruit' ]; // apple
print $arr [ fruit ]; // carrot
// The following is okay, as it's inside a string. Constants are not looked for
// within strings, so no E_NOTICE occurs here
print "Hello $arr [ fruit ] " ; // Hello apple
// With one exception: braces surrounding arrays within strings allows constants
// to be interpreted
print "Hello { $arr [ fruit ]} " ; // Hello carrot
print "Hello { $arr [ 'fruit' ]} " ; // Hello apple
// This will not work, and will result in a parse error, such as:
// Parse error: parse error, expecting T_STRING' or T_VARIABLE' or T_NUM_STRING'
// This of course applies to using superglobals in strings as well
print "Hello $arr [ 'fruit']" ;
print "Hello $_GET [ 'foo']" ;
// Concatenation is another option
print "Hello " . $arr [ 'fruit' ]; // Hello apple
?>
当打开 error_reporting 来显示 E_NOTICE 级别的错误(将其设为 E_ALL )时将看到这些错误。默认情况下 error_reporting 被关闭不显示这些。
和在语法一节中规定的一样,在方括号(“[”和“]”)之间必须有一个表达式。这意味着可以这样写:
<?php
echo $arr [ somefunc ( $bar )];
?>
这是一个用函数返回值作为数组索引的例子。PHP 也可以用已知常量,可能之前已经见过:
<?php
$error_descriptions [ E_ERROR ] = "A fatal error has occured" ;
$error_descriptions [ E_WARNING ] = "PHP issued a warning" ;
$error_descriptions [ E_NOTICE ] = "This is just an informal notice" ;
?>
注意 E_ERROR 也是个合法的标识符,就和第一个例子中的 bar 一样。但是上一个例子实际上和如下写法是一样的:
<?php
$error_descriptions [ 1 ] = "A fatal error has occured" ;
$error_descriptions [ 2 ] = "PHP issued a warning" ;
$error_descriptions [ 8 ] = "This is just an informal notice" ;
?>
因为 E_ERROR 等于 1,等等。
那么为什么这样做不好?
也许有一天,PHP 开发小组可能会想新增一个常量或者关键字,或者用户可能希望以后在自己的程序中引入新的常量,那就有麻烦了。例如已经不能这样用 empty 和 default 这两个词了,因为他们是保留字。
-
Note: 重申一次,在双引号字符串中,不给索引加上引号是合法的因此 "$foo[bar]" 是合法的(“合法”的原文为 valid。在实际测试中,这么做确实可以访问数组的该元素,但是会报一个常量未定义的 notice。无论如何,强烈建议不要使用 $foo[bar]这样的写法,而要使用 $foo['bar'] 来访问数组中元素。--haohappy 注)。至于为什么参见以上的例子和字符串中的变量解析中的解释。
-
转换为数组
对于任意 integer , float , string , boolean 和 resource 类型,如果将一个值转换为数组,将得到一个仅有一个元素的数组,其下标为 0,该元素即为此标量的值。换句话说,(array)$scalarValue 与 array($scalarValue) 完全一样。
如果一个 object 类型转换为 array ,则结果为一个数组,其单元为该对象的属性。键名将为成员变量名,不过有几点例外:整数属性不可访问;私有变量前会加上类名作前缀;保护变量前会加上一个 '*' 做前缀。这些前缀的前后都各有一个 NULL 字符。这会导致一些不可预知的行为:
<?php
class A {
private $A ; // This will become '\0A\0A'
}
class B extends A {
private $A ; // This will become '\0B\0A'
public $AA ; // This will become 'AA'
}
var_dump ((array) new B ());
?>
上例会有两个键名为 'AA',不过其中一个实际上是 '\0A\0A'。
将 NULL 转换为 array 会得到一个空的数组。
-
比较:可以用 array_diff() 和数组运算符来比较数组。
-
示例
PHP 中的数组类型有非常多的用途。以下是一些示例:
<?php
// This:
$a = array( 'color' => 'red' ,
'taste' => 'sweet' ,
'shape' => 'round' ,
'name' => 'apple' ,
4 // key will be 0
);
$b = array( 'a' , 'b' , 'c' );
// . . .is completely equivalent with this:
$a = array();
$a [ 'color' ] = 'red' ;
$a [ 'taste' ] = 'sweet' ;
$a [ 'shape' ] = 'round' ;
$a [ 'name' ] = 'apple' ;
$a [] = 4 ; // key will be 0
$b = array();
$b [] = 'a' ;
$b [] = 'b' ;
$b [] = 'c' ;
// After the above code is executed, $a will be the array
// array('color' => 'red', 'taste' => 'sweet', 'shape' => 'round',
// 'name' => 'apple', 0 => 4), and $b will be the array
// array(0 => 'a', 1 => 'b', 2 => 'c'), or simply array('a', 'b', 'c').
?>
Example #8 使用 array()
<?php
// Array as (property-)map
$map = array( 'version' => 4 ,
'OS' => 'Linux' ,
'lang' => 'english' ,
'short_tags' => true
);
// strictly numerical keys
$array = array( 7 ,
8 ,
0 ,
156 ,
- 10
);
// this is the same as array(0 => 7, 1 => 8, ...)
$switching = array( 10 , // key = 0
5 => 6 ,
3 => 7 ,
'a' => 4 ,
11 , // key = 6 (maximum of integer-indices was 5)
'8' => 2 , // key = 8 (integer!)
'02' => 77 , // key = '02'
0 => 12 // the value 10 will be overwritten by 12
);
// empty array
$empty = array();
?>
Example #9 集合
<?php
$colors = array( 'red' , 'blue' , 'green' , 'yellow' );
foreach ( $colors as $color ) {
echo "Do you like $color ?\n" ;
}
?>
以上例程会输出:
Do you like red?
Do you like blue?
Do you like green?
Do you like yellow?
直接改变数组的值自 PHP 5 起可以通过引用传递来做到。之前的版本需要需要采取变通的方法:
Example #10 在循环中改变单元
<?php
// PHP 5
foreach ( $colors as & $color ) {
$color = strtoupper ( $color );
}
unset( $color ); /* ensure that following writes to
$color will not modify the last array element */
// Workaround for older versions
foreach ( $colors as $key => $color ) {
$colors [ $key ] = strtoupper ( $color );
}
print_r ( $colors );
?>
以上例程会输出:
Array
(
[0] => RED
[1] => BLUE
[2] => GREEN
[3] => YELLOW
)
本例生成一个下标从 1 开始的数组。
Example #11 下标从 1 开始的数组
<?php
$firstquarter = array( 1 => 'January' , 'February' , 'March' );
print_r ( $firstquarter );
?>
以上例程会输出:
Array
(
[1] => 'January'
[2] => 'February'
[3] => 'March'
)
Example #12 填充数组
<?php
// fill an array with all items from a directory
$handle = opendir ( '.' );
while ( false !== ( $file = readdir ( $handle ))) {
$files [] = $file ;
}
closedir ( $handle );
?>
数组是有序的。也可以使用不同的排序函数来改变顺序。更多信息参见数组函数。可以用 count() 函数来数出数组中元素的个数。
Example #13 数组排序
<?php
sort ( $files );
print_r ( $files );
?>
因为数组中的值可以为任意值,也可是另一个数组。这样可以产生递归或多维数组。
Example #14 递归和多维数组
<?php
$fruits = array ( "fruits" => array ( "a" => "orange" ,
"b" => "banana" ,
"c" => "apple"
),
"numbers" => array ( 1 ,
2 ,
3 ,
4 ,
5 ,
6
),
"holes" => array ( "first" ,
5 => "second" ,
"third"
)
);
// Some examples to address values in the array above
echo $fruits [ "holes" ][ 5 ]; // prints "second"
echo $fruits [ "fruits" ][ "a" ]; // prints "orange"
unset( $fruits [ "holes" ][ 0 ]); // remove "first"
// Create a new multi-dimensional array
$juices [ "apple" ][ "green" ] = "good" ;
?>
数组(Array) 的赋值总是会涉及到值的拷贝。使用引用运算符通过引用来拷贝数组。
<?php
$arr1 = array( 2 , 3 );
$arr2 = $arr1 ;
$arr2 [] = 4 ; // $arr2 is changed,
// $arr1 is still array(2, 3)
$arr3 = & $arr1 ;
$arr3 [] = 4 ; // now $arr1 and $arr3 are the same
?>
(七)Object 对象
- 对象初始化
要创建一个新的对象 object ,使用 new 语句实例化一个类:
<?php
class foo
{
function do_foo ()
{
echo "Doing foo." ;
}
}
$bar = new foo ;
$bar -> do_foo ();
?>
详细讨论参见手册中类与对象章节。
- 转换为对象
如果将一个对象转换成对象,它将不会有任何变化。如果其它任何类型的值被转换成对象,将会创建一个内置类 stdClass 的实例。如果该值为 NULL ,则新的实例为空。数组转换成对象将使键名成为属性名并具有相对应的值。对于任何其它的值,名为 scalar 的成员变量将包含该值。
<?php
$obj = (object) 'ciao' ;
echo $obj -> scalar ; // outputs 'ciao'
?>
(八)Resource 资源类型
- 资源 resource
是一种特殊变量,保存了到外部资源的一个引用。资源是通过专门的函数来建立和使用的。所有这些函数及其相应资源类型见附录。
参见 get_resource_type() 。
- 转换为资源
由于资源类型变量保存有为打开文件、数据库连接、图形画布区域等的特殊句柄,因此将其它类型的值转换为资源没有意义。
- 释放资源
由于 PHP 4 Zend 引擎引进了引用计数系统,可以自动检测到一个资源不再被引用了(和 Java 一样)。这种情况下此资源使用的所有外部资源都会被垃圾回收系统释放。因此,很少需要手工释放内存。
- Note: 持久数据库连接比较特殊,它们不会被垃圾回收系统销毁。参见数据库永久连接一章。
(九)NULL
特殊的 NULL 值表示一个变量没有值。 NULL 类型唯一可能的值就是 NULL 。
在下列情况下一个变量被认为是 NULL :
- 被赋值为 NULL 。
- 尚未被赋值。
- 被 unset() 。
语法
NULL 类型只有一个值,就是不区分大小写的常量 NULL 。
<?php
$var = NULL ;
?>
参见 is_null() 和 unset() 。
- 转换到 NULL
使用 (unset) $var 将一个变量转换为 null 将不会删除该变量或 unset 其值。仅是返回 NULL 值而已。
(十)Callback 回调类型
自 PHP 5.4 起可用 callable 类型指定回调类型 callback。本文档基于同样理由使用 callback 类型信息。
一些函数如 call_user_func() 或 usort() 可以接受用户自定义的回调函数作为参数。回调函数不止可以是简单函数,还可以是对象的方法,包括静态类方法。
- 传递
一个 PHP 的函数以 string 类型传递其名称。可以使用任何内置或用户自定义函数,但除了语言结构例如: array() , echo , empty() , eval() , exit() , isset() , list() , print 或 unset() 。
一个已实例化的对象的方法被作为数组传递,下标 0 包含该对象,下标 1 包含方法名。
静态类方法也可不经实例化该类的对象而传递,只要在下标 0 中包含类名而不是对象。自 PHP 5.2.3 起,也可以传递 'ClassName::methodName'。
除了普通的用户自定义函数外, create_function() 可以用来创建一个匿名回调函数。自 PHP 5.3.0 起也可传递 closure 给回调参数。
Example #1 回调函数示例
<?php
// An example callback function
function my_callback_function () {
echo 'hello world!' ;
}
// An example callback method
class MyClass {
static function myCallbackMethod () {
echo 'Hello World!' ;
}
}
// Type 1: Simple callback
call_user_func ( 'my_callback_function' );
// Type 2: Static class method call
call_user_func (array( 'MyClass' , 'myCallbackMethod' ));
// Type 3: Object method call
$obj = new MyClass ();
call_user_func (array( $obj , 'myCallbackMethod' ));
// Type 4: Static class method call (As of PHP 5.2.3)
call_user_func ( 'MyClass::myCallbackMethod' );
// Type 5: Relative static class method call (As of PHP 5.3.0)
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' )); // A
?>
Example #2 使用 Closure 的示例
<?php
// Our closure
$double = function( $a ) {
return $a * 2 ;
};
// This is our range of numbers
$numbers = range ( 1 , 5 );
// Use the closure as a callback here to
// double the size of each element in our
// range
$new_numbers = array_map ( $double , $numbers );
print implode ( ' ' , $new_numbers );
?>
以上例程会输出:
2 4 6 8 10
-
Note: 在 PHP 4 中,需要使用一个引用来创建一个指向具体对象的回调函数,而不是一个拷贝。参见引用的解释。
-
Note: 在函数中注册有多个回调内容时(如使用 call_user_func() 与 call_user_func_array() ),如在前一个回调中有未捕获的异常,其后的将不再被调用。
(十一)本文档中使用的伪类型与变量
- mixed
mixed 说明一个参数可以接受多种不同的(但不一定是所有的)类型。
例如 gettype() 可以接受所有的 PHP 类型, str_replace() 可以接受字符串和数组。
- number
number 说明一个参数可以是 integer 或者 float 。
- callback
本文档中在 PHP 5.4 引入 callable 类型之前使用 了 callback 伪类型。二者含义完全相同。
- void
void 作为返回类型意味着函数的返回值是无用的。void 作为参数列表意味着函数不接受任何参数。
- ...
在函数原型中,$... 表示等等的意思。当一个函数可以接受任意个参数时使用此变量名。
(十二)类型转换的判别
PHP在变量定义中不需要(或不支持)明确的类型定义;变量类型是根据使用该变量的上下文所决定的。也就是说,如果把一个 string 值赋给变量 $var , $var 就成了一个 string 。如果又把一个 integer 赋给 $var ,那它就成了一个 integer 。
PHP的自动类型转换的一个例子是加法运算符“+”。如果任何一个操作数是 float ,则所有的操作数都被当成 float ,结果也是 float 。否则操作数会被解释为 integer ,结果也是 integer 。注意这并没有改变这些操作数本身的类型;改变的仅是这些操作数如何被求值以及表达式本身的类型。
<?php
$foo = "0" ; // $foo 是字符串 (ASCII 48)
$foo += 2 ; // $foo 现在是一个整数 (2)
$foo = $foo + 1.3 ; // $foo 现在是一个浮点数 (3.3)
$foo = 5 + "10 Little Piggies" ; // $foo 是整数 (15)
$foo = 5 + "10 Small Pigs" ; // $foo 是整数 (15)
?>
如果上面两个例子看上去古怪的话,参见字符串转换为数值。
如果要强制将一个变量当作某种类型来求值,参见类型强制转换一节。如果要改变一个变量的类型,参见 settype() 。
如果想要测试本节中任何例子的话,可以用 var_dump() 函数。
- Note: 自动转换为 数组 的行为目前没有定义。
此外,由于 PHP 支持使用和数组下标同样的语法访问字符串下标,以下例子在所有 PHP 版本中都有效:
<?php
$a = 'car' ; // $a is a string
$a [ 0 ] = 'b' ; // $a is still a string
echo $a ; // bar
?>
请参阅存取和修改字符串中的字符一节以获取更多信息。
- 类型强制转换
PHP 中的类型强制转换和 C 中的非常像:在要转换的变量之前加上用括号括起来的目标类型。
<?php
$foo = 10 ; // $foo is an integer
$bar = (boolean) $foo ; // $bar is a boolean
?>
允许的强制转换有:
- (int), (integer) - 转换为整形 integer
- (bool), (boolean) - 转换为布尔类型 boolean
- (float), (double), (real) - 转换为浮点型 float
- (string) - 转换为字符串 string
- (array) - 转换为数组 array
- (object) - 转换为对象 object
- (unset) - 转换为 NULL (PHP 5)
(binary) 转换和 b 前缀转换支持为 PHP 5.2.1 新增。
注意在括号内允许有空格和制表符,所以下面两个例子功能相同:
<?php
$foo = (int) $bar ;
$foo = ( int ) $bar ;
?>
将字符串文字和变量转换为二进制字符串:
<?php
$binary = (binary) $string ;
$binary = b"binary string" ;
?>
- Note:可以将变量放置在双引号中的方式来代替将变量转换成字符串:
<?php
$foo = 10 ; // $foo 是一个整数
$str = " $foo " ; // $str 是一个字符串
$fst = (string) $foo ; // $fst 也是一个字符串
// 输出 "they are the same"
if ( $fst === $str ) {
echo "they are the same" ;
}
?>
有时在类型之间强制转换时确切地会发生什么可能不是很明显。更多信息见如下小节:
- 转换为布尔型
- 转换为整型
- 转换为浮点型
- 转换为字符串
- 转换为数组
- 转换为对象
- 转换为资源
- 转换为 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' ; // 合法变量名;可以用中文
?>
变量默认总是传值赋值。那也就是说,当将一个表达式的值赋予一个变量时,整个原始表达式的值被赋值到目标变量。这意味着,例如,当一个变量的值赋予另外一个变量时,改变其中一个变量的值,将不会影响到另外一个变量。有关这种类型的赋值操作,请参阅表达式一章。
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 中)默认值是空字符串以及数组变量的默认值是空数组。
Example #1 未初始化变量的默认值
<?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'] 代替 $DOCUMENT_ROOT ,又如,使用 $_GET['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 ;
?>
$GLOBALS 是一个关联数组,每一个变量为一个元素,键名对应变量名,值对应变量的内容。 $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 的值设为 0 并输出 0。将变量加一的 $a ++ 没有作用,因为一旦退出本函数则变量 $a 就不存在了。要写一个不会丢失本次计数值的计数函数,要将变量 $a 定义为静态的:
Example #5 使用静态变量的例子
<?php
function test ()
{
static $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 ;
}
?>
静态声明是在编译时解析的。
-
Note: 在函数之外使用 global 关键字不算错。可以用于在一个函数之内包含文件时。
-
全局和静态变量的引用
在 Zend 引擎 1 代,它驱动了 PHP4,对于变量的 static 和 global 定义是以引用的方式实现的。例如,在一个函数域内部用 global 语句导入的一个真正的全局变量实际上是建立了一个到全局变量的引用。这有可能导致预料之外的行为,如以下例子所演示的:
<?php
function test_global_ref () {
global $obj ;
$obj = &new stdclass ;
}
function test_global_noref () {
global $obj ;
$obj = new stdclass ;
}
test_global_ref ();
var_dump ( $obj );
test_global_noref ();
var_dump ( $obj );
?>
以上例程会输出:
NULL
object(stdClass)(0) {
}
类似的行为也适用于 static 语句。引用并不是静态地存储的:
<?php
function & get_instance_ref () {
static $obj ;
echo 'Static object: ' ;
var_dump ( $obj );
if (!isset( $obj )) {
// 将一个引用赋值给静态变量
$obj = &new stdclass ;
}
$obj -> property ++;
return $obj ;
}
function & get_instance_noref () {
static $obj ;
echo 'Static object: ' ;
var_dump ( $obj );
if (!isset( $obj )) {
// 将一个对象赋值给静态变量
$obj = new stdclass ;
}
$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)(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() 或 SimpleXML)。
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" ;
echo $foo -> $baz [ 1 ] . "\n" ;
$start = 'b' ;
$end = 'ar' ;
echo $foo ->{ $start . $end } . "\n" ;
$arr = 'arr' ;
echo $foo -> $arr [ 1 ] . "\n" ;
echo $foo ->{ $arr }[ 1 ] . "\n" ;
?>
以上例程会输出:
I am bar.
I am bar.
I am bar.
I am r.
I am B.
- Warning 注意,在 PHP 的函数和类的方法中,超全局变量不能用作可变变量。$this 变量也是一个特殊变量,不能被动态引用。
(五)来自 PHP 之外的变量
- HTML 表单(GET 和 POST)
当一个表单提交给 PHP 脚本时,表单中的信息会自动在脚本中可用。有很多方法访问此信息,例如:
Example #1 一个简单的 HTML 表单
<form action="foo.php" method="POST">
Name: <input type="text" name="username"><br />
Email: <input type="text" name="email"><br />
<input type="submit" name="submit" value="Submit me!" />
</form>
根据特定的设置和个人的喜好,有很多种方法访问 HTML 表单中的数据。例如:
Example #2 从一个简单的 POST HTML 表单访问数据
<?php
// 自 PHP 4.1.0 起可用
echo $_POST['username'];
echo $_REQUEST['username'];
import_request_variables('p', 'p_');
echo $p_username;// 自 PHP 5.0.0 起,这些长格式的预定义变量
// 可用 register_long_arrays 指令关闭。 echo $HTTP_POST_VARS['username'];// 如果 PHP 指令 register_globals = on 时可用。不过自
// PHP 4.2.0 起默认值为 register_globals = off。
// 不提倡使用/依赖此种方法。 echo $username;
?>
使用 GET 表单也类似,只不过要用适当的 GET 预定义变量。GET 也适用于 QUERY_STRING(URL 中在“?”之后的信息)。因此,举例说,http://www.example.com/test.php?id=3
包含有可用 $_GET['id'] 来访问的 GET 数据。参见 $_REQUEST 和 import_request_variables() 。
-
Note: 超全局数组例如 $_POST 和 $_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。
PHP 也懂得表单变量上下文中的数组(参见相关常见问题)。例如可以将相关的变量编成组,或者用此特性从多选输入框中取得值。例如,将一个表单 POST 给自己并在提交时显示数据:
Example #3 更复杂的表单变量
<?php
if (isset( $_POST [ 'action' ]) && $_POST [ 'action' ] == 'submitted' ) {
echo '<pre>' ;
print_r ( $_POST );
echo '<a href="' . $_SERVER [ 'PHP_SELF' ] . '">Please try again</a>' ;
echo '</pre>' ;
} else {
?>
<form action="<?php echo $_SERVER [ 'PHP_SELF' ]; ?>" method="post">
Name: <input type="text" name="personal[name]"><br />
Email: <input type="text" name="personal[email]"><br />
Beer: <br>
<select multiple name="beer[]">
<option value="warthog">Warthog</option>
<option value="guinness">Guinness</option>
<option value="stuttgarter">Stuttgarter Schwabenbr</option>
</select><br />
<input type="hidden" name="action" value="submitted" />
<input type="submit" name="submit" value="submit me!" />
</form>
<?php
}
?>
- IMAGE SUBMIT 变量名
当提交表单时,可以用一幅图像代替标准的提交按钮,用类似这样的标记:
<input type="image" src="image.gif" name="sub" />
当用户点击到图像中的某处时,相应的表单会被传送到服务器,并加上两个变量 sub_x 和 sub_y 。它们包含了用户点击图像的坐标。有经验的用户可能会注意到被浏览器发送的实际变量名包含的是一个点而不是下划线(即 sub.x 和 sub.y),但 PHP 自动将点转换成了下划线。
- HTTP Cookies
PHP 透明地支持 » RFC 6265定义中的 HTTP cookies。Cookies 是一种在远端浏览器端存储数据并能追踪或识别再次访问的用户的机制。可以用 setcookie() 函数设定 cookies。Cookies 是 HTTP 信息头中的一部分,因此 SetCookie 函数必须在向浏览器发送任何输出之前调用。对于 header() 函数也有同样的限制。Cookie 数据会在相应的 cookie 数据数组中可用,例如 $_COOKIE , $HTTP_COOKIE_VARS 和 $_REQUEST 。更多细节和例子见 setcookie() 手册页面。
如果要将多个值赋给一个 cookie 变量,必须将其赋成数组。例如:
<?php
setcookie ( "MyCookie[foo]" , 'Testing 1' , time ()+ 3600 );
setcookie ( "MyCookie[bar]" , 'Testing 2' , time ()+ 3600 );
?>
这将会建立两个单独的 cookie,尽管 MyCookie 在脚本中是一个单一的数组。如果想在仅仅一个 cookie 中设定多个值,考虑先在值上使用 serialize() 或 explode() 。
注意在浏览器中一个 cookie 会替换掉上一个同名的 cookie,除非路径或者域不同。因此对于购物车程序可以保留一个计数器并一起传递,例如:
Example #4 一个 setcookie() 的示例
<?php
if (isset( $_COOKIE [ 'count' ])) {
$count = $_COOKIE [ 'count' ] + 1 ;
} else {
$count = 1 ;
}
setcookie ( 'count' , $count , time ()+ 3600 );
setcookie ( "Cart[ $count ]" , $item , time ()+ 3600 );
?>
- 变量名中的点
通常,PHP 不会改变传递给脚本中的变量名。然而应该注意到点(句号)不是 PHP 变量名中的合法字符。至于原因,看看:
<?php
$varname . ext ; /* 非法变量名 */
?>
这时,解析器看到是一个名为 $varname 的变量,后面跟着一个字符串连接运算符,后面跟着一个裸字符串(即没有加引号的字符串,且不匹配任何已知的健名或保留字)'ext'。很明显这不是想要的结果。
出于此原因,要注意 PHP 将会自动将变量名中的点替换成下划线。
- 确定变量类型
因为 PHP 会判断变量类型并在需要时进行转换(通常情况下),因此在某一时刻给定的变量是何种类型并不明显。PHP 包括几个函数可以判断变量的类型,例如: gettype() , is_array() , is_float() , is_int() , is_object() 和 is_string() 。参见类型一章。
四、常量
Table of Contents
- 语法
- 魔术常量
常量是一个简单值的标识符(名字)。如同其名称所暗示的,在脚本执行期间该值不能改变(除了所谓的魔术常量,它们其实不是常量)。常量默认为大小写敏感。传统上常量标识符总是大写的。
常量名和其它任何 PHP 标签遵循同样的命名规则。合法的常量名以字母或下划线开始,后面跟着任何字母,数字或下划线。用正则表达式是这样表达的:[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*
。
Tip 请参见用户空间命名指南。
Example #1 合法与非法的常量名
<?php
// 合法的常量名
define ( "FOO" , "something" );
define ( "FOO2" , "something else" );
define ( "FOO_BAR" , "something more" );
// 非法的常量名
define ( "2FOO" , "something" );
// 下面的定义是合法的,但应该避免这样做:(自定义常量不要以__开头)
// 也许将来有一天PHP会定义一个__FOO__的魔术常量
// 这样就会与你的代码相冲突
define ( "__FOO__" , "something" );
?>
- Note: 在这里,字母指的是 a-z,A-Z,以及从 127 到 255(0x7f-0xff)的 ASCII 字符。
和 superglobals 一样,常量的范围是全局的。不用管作用区域就可以在脚本的任何地方访问常量。有关作用区域的更多信息请阅读手册中的变量范围。
(一)语法
可以用 define() 函数来定义常量,在 PHP 5.3.0 以后,可以使用 const 关键字在类定义之外定义常量。一个常量一旦被定义,就不能再改变或者取消定义。
常量只能包含标量数据( boolean , integer , float 和 string )。可以定义 resource 常量,但应尽量避免,因为会造成不可预料的结果。
可以简单的通过指定其名字来取得常量的值,与变量不同,不应该在常量前面加上 $ 符号。如果常量名是动态的,也可以用函数 constant() 来获取常量的值。用 get_defined_constants() 可以获得所有已定义的常量列表。
- Note: 常量和(全局)变量在不同的名字空间中。这意味着例如 TRUE 和 $TRUE 是不同的。
如果使用了一个未定义的常量,PHP 假定想要的是该常量本身的名字,如同用字符串调用它一样(CONSTANT 对应 "CONSTANT")。此时将发出一个 E_NOTICE 级的错误。参见手册中为什么 $foo[bar] 是错误的(除非事先用 define() 将 bar 定义为一个常量)。如果只想检查是否定义了某常量,用 defined() 函数。
常量和变量有如下不同:
- 常量前面没有美元符号($);
- 常量只能用 define() 函数定义,而不能通过赋值语句;
- 常量可以不用理会变量的作用域而在任何地方定义和访问;
- 常量一旦定义就不能被重新定义或者取消定义;
- 常量的值只能是标量。
Example #1 定义常量
<?php
define ( "CONSTANT" , "Hello world." );
echo CONSTANT ; // outputs "Hello world."
echo Constant ; // 输出 "Constant" 并发出一个提示级别错误信息
?>
Example #2 使用关键字 const 定义常量
<?php
// 以下代码在 PHP 5.3.0 后可以正常工作
const CONSTANT = 'Hello World' ;
echo CONSTANT ;
?>
Note: 和使用 define() 来定义常量相反的是,使用 const 关键字定义常量必须处于最顶端的作用区域,因为用此方法是在编译时定义的。这就意味着不能在函数内,循环内以及 if 语句之内用 const 来定义常量。
(二)魔术常量
PHP 向它运行的任何脚本提供了大量的预定义常量。不过很多常量都是由不同的扩展库定义的,只有在加载了这些扩展库时才会出现,或者动态加载后,或者在编译时已经包括进去了。
有八个魔术常量它们的值随着它们在代码中的位置改变而改变。例如 LINE 的值就依赖于它在脚本中所处的行来决定。这些特殊的常量不区分大小写,如下:
- 几个 PHP 的“魔术常量”
名称 | 说明 |
---|---|
LINE | 文件中的当前行号。 |
FILE | 文件的完整路径和文件名。如果用在被包含文件中,则返回被包含的文件名。自 PHP 4.0.2 起, FILE 总是包含一个绝对路径(如果是符号连接,则是解析后的绝对路径),而在此之前的版本有时会包含一个相对路径。 |
DIR | 文件所在的目录。如果用在被包括文件中,则返回被包括的文件所在的目录。它等价于 dirname(FILE)。除非是根目录,否则目录中名不包括末尾的斜杠。(PHP 5.3.0中新增) |
FUNCTION | 函数名称(PHP 4.3.0 新加)。自 PHP 5 起本常量返回该函数被定义时的名字(区分大小写)。在 PHP 4 中该值总是小写字母的。 |
CLASS | 类的名称(PHP 4.3.0 新加)。自 PHP 5 起本常量返回该类被定义时的名字(区分大小写)。在 PHP 4 中该值总是小写字母的。类名包括其被声明的作用区域(例如 Foo\Bar)。注意自 PHP 5.4 起 CLASS 对 trait 也起作用。当用在 trait 方法中时,CLASS 是调用 trait 方法的类的名字。 |
TRAIT | Trait 的名字(PHP 5.4.0 新加)。自 PHP 5.4 起此常量返回 trait 被定义时的名字(区分大小写)。Trait 名包括其被声明的作用区域(例如 Foo\Bar)。 |
METHOD | 类的方法名(PHP 5.0.0 新加)。返回该方法被定义时的名字(区分大小写)。 |
NAMESPACE | 当前命名空间的名称(区分大小写)。此常量是在编译时定义的(PHP 5.3.0 新增)。 |
参见 get_class() , get_object_vars() , file_exists() 和 function_exists() 。
五、表达式
表达式是 PHP 最重要的基石。在 PHP 中,几乎所写的任何东西都是一个表达式。简单但却最精确的定义一个表达式的方式就是“任何有值的东西”。
最基本的表达式形式是常量和变量。当键入“ $a = 5”,即将值“5”分配给变量 $a 。“5”,很明显,其值为 5,换句话说“5”是一个值为 5 的表达式(在这里,“5”是一个整型常量)。
赋值之后,所期待情况是 $a 的值为 5,因而如果写下 $b = $a ,期望的是它犹如 $b = 5 一样。换句话说, $a 是一个值也为 5 的表达式。如果一切运行正确,那这正是将要发生的正确结果。
稍微复杂的表达式例子就是函数。例如,考虑下面的函数:
<?php
function foo ()
{
return 5 ;
}
?>
假定已经熟悉了函数的概念(果不是的话,请看一下函数的相关章节),那么键入 $c = foo() 从本质上来说就如写下 $c = 5,这没错。函数也是表达式,表达式的值即为它们的返回值。既然 foo() 返回 5,表达式“foo()”的值也是 5。通常函数不会仅仅返回一个静态值,而可能会计算一些东西。
当然,PHP 中的值常常并非是整型的。PHP 支持四种标量值(标量值不能拆分为更小的单元,例如和数组不同)类型:整型值( integer ),浮点数值( float ),字符串值( string )和布尔值( boolean )。PHP 也支持两种复合类型:数组和对象。这两种类型具可以赋值给变量或者从函数返回。
PHP 和其它语言一样在表达式的道路上发展,但推进得更深远。PHP 是一种面向表达式的语言,从这一方面来讲几乎一切都是表达式。考虑刚才已经研究过的例子,“ $a = 5”。很显然这里涉及到两个值,整型常量 5 的值以及而且变量 $a 的值,它也被更新为 5。但是事实是这里还涉及到一个额外的值,即附值语句本身的值。赋值语句本身求值为被赋的值,即 5。实际上这意味着“ $a = 5”,不必管它是做什么的,是一个值为 5 的表达式。因而,这样写“ $b = ( $a = 5)”和这样写“ $a =5; $b =5”(分号标志着语句的结束)是一样的。因为赋值操作的顺序是由右到左的,也可以这么写“ $b = $a =5”。
另外一个很好的面向表达式的例子就是前、后递增和递减。PHP 和多数其它语言的用户应该比较熟悉变量 ++ 和变量 -- 符号。即递增和递减运算符。在 PHP/FI 2 中,语句“$a++”没有值(不是表达式),这样的话你便不能为其赋值或者以任何其它方式来使用它。PHP 通过将其变为了表达式,类似 C 语言,增强了递增/递减的能力。在 PHP 和 C 语言 中,有两种类型的递增前递增和后递增,本质上来讲,前递增和后递增均增加了变量的值,并且对于变量的影响是相同的。不同的是递增表达式的值。前递增,写做“++$variable”,求增加后的值(PHP 在读取变量的值之前,增加变量的值,因而称之为“前递增”)。后递增,写做“$variable++”,求变量未递增之前的原始值(PHP 在读取变量的值之后,增加变量的值,因而叫做“后递增”)。
一个常用到表达式类型是比较表达式。这些表达式求值 FALSE 或 TRUE 。PHP 支持 >(大于),>=(大于等于),==(等于),!=(不等于),<(小于),<= (小于等于)。PHP 还支持全等运算符 ===(值和类型均相同)和非全等运算符 !==(值或者类型不同)。这些表达式都是在条件判断语句,比如,if 语句中最常用的。
这里,将要研究的最后一个例子是组合的运算赋值表达式。已经知道如果想要为变量 $a 加1,可以简单的写“$a++”或者“++$a”。但是如果想为变量增加大于 1 的值,比如 3,该怎么做?可以多次写“$a++”,但这样明显不是一种高效舒适的方法,一个更加通用的做法是“$a = $a + 3”。“$a + 3”计算 $a 加上 3 的值,并且得到的值重新赋予变量 $a,于是 $a 的值增加了3。在 PHP 及其它几种类似 C 的语言中,可以以一种更加简短的形式完成上述功能,因而也更加清楚快捷。为 $a 的当前值加 3,可以这样写:“$a += 3”。这里的意思是“取变量 $a 的值,加 3,得到的结果再次分配给变量 $a”。除了更简略和清楚外,也可以更快的运行。“$a += 3”的值,如同一个正常赋值操作的值,是赋值后的值。注意它不是 3,而是 $a 的值加上3 之后的值(此值将被赋给 $a)。任何二元运算符都可以用运算赋值模式,例如“$a -= 5”(从变量 $a 的值中减去 5),“$b *= 7”(变量 $b 乘以 7),等等。
还有一个表达式,如果没有在别的语言中看到过的话,可能看上去很奇怪,即三元条件运算符:
$first ? $second : $third
如果第一个子表达式的值是 TRUE (非零),那么计算第二个子表达式的值,其值即为整个表达式的值。否则,将是第三个子表达式的值。
下面的例子一般来说应该有助于理解前、后递增和表达式:
<?php
function double ( $i )
{
return $i * 2 ;
}
$b = $a = 5 ; /* assign the value five into the variable $a and $b */
$c = $a ++; /* post-increment, assign original value of $a
(5) to $c */
$e = $d = ++ $b ; /* pre-increment, assign the incremented value of
$b (6) to $d and $e */
/* at this point, both $d and $e are equal to 6 */
$f = double ( $d ++); /* assign twice the value of $d before
the increment, 2*6 = 12 to $f */
$g = double (++ $e ); /* assign twice the value of $e after
the increment, 2*7 = 14 to $g */
$h = $g += 10 ; /* first, $g is incremented by 10 and ends with the
value of 24. the value of the assignment (24) is
then assigned into $h, and $h ends with the value
of 24 as well. */
?>
一些表达式可以被当成语句。这时,一条语句的形式是 'expr' ';',即一个表达式加一个分号结尾。在“$b=$a=5;”中,$a=5 是一个有效的表达式,但它本身不是一条语句。“$b=$a=5;”是一条有效的语句。
最后一件值得提起的事情就是表达式的真值。在许多事件中,大体上主要是在条件执行和循环中,不要专注于表达式中明确的值,反而要注意表达式的值是否是 TRUE 或者 FALSE 。常量 TRUE 和 FALSE (大小写无关)是两种可能的 Boolean 值。如果有必要,一个表达式将自动转换为 Boolean。参见类型强制转换一节。
PHP 提供了一套完整强大的表达式,而为它提供完整的文件资料已经超出了本手册的范围。上面的例子应该为你提供了一个好的关于什么是表达式和怎样构建一个有用的表达式的概念。在本手册的其余部分,我们将始终使用 expr 来表示一个有效的 PHP 表达式。
六、运算符
Table of Contents
- 运算符优先级
- 算术运算符
- 赋值运算符
- 位运算符
- 比较运算符
- 错误控制运算符
- 执行运算符
- 递增/递减运算符
- 逻辑运算符
- 字符串运算符
- 数组运算符
- 类型运算符
运算符是可以通过给出的一或多个值(用编程行话来说,表达式)来产生另一个值(因而整个结构成为一个表达式)的东西。
运算符可按照其能接受几个值来分组。一元运算符只能接受一个值,例如 !(逻辑取反运算符)或 ++(递增运算符)。二元运算符可接受两个值,例如熟悉的算术运算符 +(加)和 -(减),大多数 PHP 运算符都是这种。最后是唯一的三元运算符 ? :,可接受三个值;通常就简单称之为“三元运算符”(尽管称之为条件运算符可能更合适)。
PHP 的运算符完整列表见下节运算符优先级。该节也解释了运算符优先级和结合方向,这控制着在表达式包含有若干个不同运算符时究竟怎样对其求值。
(一)运算符优先级
运算符优先级指定了两个表达式绑定得有多“紧密”。例如,表达式 1 + 5 3 的结果是 16 而不是 18 是因为乘号(“”)的优先级比加号(“+”)高。必要时可以用括号来强制改变优先级。例如:(1 + 5) * 3 的值为 18。
如果运算符优先级相同,其结合方向决定着应该从右向左求值,还是从左向右求值——见下例。
下表按照优先级从高到低列出了运算符。同一行中的运算符具有相同优先级,此时它们的结合方向决定求值顺序。
- 运算符优先级
结合方向 | 运算符 | 附加信息 |
---|---|---|
无 | clone new | clone 和 new |
左 | [ | array() |
右 | ++ -- ~ (int) (float) (string) (array) (object) (bool) @ | 类型和递增/递减 |
无 | instanceof | 类型 |
右 | ! | 逻辑运算符 |
左 | * / % | 算术运算符 |
左 | + - . | 算术运算符和字符串运算符 |
左 | << >> | 位运算符 |
无 | == != === !== <> | 比较运算符 |
左 | & | 位运算符和引用 |
左 | ^ | 位运算符 |
左 | | |
位运算符 |
左 | && | 逻辑运算符 |
左 | || |
逻辑运算符 |
左 | ? : | 三元运算符 |
右 | = += -= *= /= .= %= &= |= ^= <<= >>= => |
赋值运算符 |
左 | and | 逻辑运算符 |
左 | xor | 逻辑运算符 |
左 | or | 逻辑运算符 |
左 | , | 多处用到 |
对具有相同优先级的运算符,左结合方向意味着将从左向右求值,右结合方向则反之。对于无结合方向具有相同优先级的运算符,该运算符有可能无法与其自身结合。举例说,在 PHP 中 1 < 2 > 1 是一个非法语句,而 1 <= 1 == 1 则不是。因为 T_IS_EQUAL 运算符的优先级比 T_IS_SMALLER_OR_EQUAL 的运算符要低。
Example #1 结合方向
<?php
$a = 3 * 3 % 5 ; // (3 * 3) % 5 = 4
$a = true ? 0 : true ? 1 : 2 ; // (true ? 0 : true) ? 1 : 2 = 2
$a = 1 ;
$b = 2 ;
$a = $b += 3 ; // $a = ($b += 3) -> $a = 5, $b = 5
// mixing ++ and + produces undefined behavior
$a = 1 ;
echo ++ $a + $a ++; // may print 4 or 5
?>
使用括号,即使在并不严格需要时,通常都可以增强代码的可读性。
- Note: 尽管 = 比其它大多数的运算符的优先级低,PHP 仍旧允许类似如下的表达式:if (!$a = foo()),在此例中 foo() 的返回值被赋给了 $a 。
(二)算术运算符
还记得学校里学到的基本数学知识吗?就和它们一样。
算术运算符
例子 | 名称 | 结果 |
---|---|---|
-$a | 取反 | $a的负值。 |
$a + $b | 加法 | $a和$b的和。 |
$a - $b | 减法 | $a和$b的差。 |
$a * $b | 乘法 | $a和$b的积。 |
$a / $b | 除法 | $a除以$b的商。 |
$a % $b | 取模 | $a除以$b的余数。 |
除法运算符总是返回浮点数。只有在下列情况例外:两个操作数都是整数(或字符串转换成的整数)并且正好能整除,这时它返回一个整数。
取模运算符的操作数在运算之前都会转换成整数(除去小数部分)。
取模运算符 % 的结果和被除数的符号(正负号)相同。即 $a % $b 的结果和 $a 的符号相同。例如:
<?php
echo ( 5 % 3 ). "\n" ; // prints 2
echo ( 5 % - 3 ). "\n" ; // prints 2
echo (- 5 % 3 ). "\n" ; // prints -2
echo (- 5 % - 3 ). "\n" ; // prints -2
?>
参见手册中的数学函数。
(三)赋值运算符
基本的赋值运算符是“=”。一开始可能会以为它是“等于”,其实不是的。它实际上意味着把右边表达式的值赋给左边的运算数。
赋值运算表达式的值也就是所赋的值。也就是说,“$a = 3”的值是 3。这样就可以做一些小技巧:
<?php
$a = ( $b = 4 ) + 5 ; // $a 现在成了 9,而 $b 成了 4。
?>
对于数组 array ,对有名字的键赋值是用“=>”运算符。此运算符的优先级和其它赋值运算符相同。
在基本赋值运算符之外,还有适合于所有二元算术,数组集合和字符串运算符的“组合运算符”,这样可以在一个表达式中使用它的值并把表达式的结果赋给它,例如:
<?php
$a = 3 ;
$a += 5 ; // sets $a to 8, as if we had said: $a = $a + 5;
$b = "Hello " ;
$b .= "There!" ; // sets $b to "Hello There!", just like $b = $b . "There!";
?>
注意赋值运算将原变量的值拷贝到新变量中(传值赋值),所以改变其中一个并不影响另一个。这也适合于在密集循环中拷贝一些值例如大数组。
在 PHP 中普通的传值赋值行为有个例外就是碰到对象 object 时,在 PHP 5 中是以引用赋值的,除非明确使用了 clone 关键字来拷贝。
- 引用赋值
PHP 支持引用赋值,使用“$var = &$othervar;”语法。引用赋值意味着两个变量指向了同一个数据,没有拷贝任何东西。
Example #1 引用赋值
<?php
$a = 3 ;
$b = & $a ; // $b 是 $a 的引用
print " $a \n" ; // 输出 3
print " $b \n" ; // 输出 3
$a = 4 ; // 修改 $a
print " $a \n" ; // 输出 4
print " $b \n" ; // 也输出 4,因为 $b 是 $a 的引用,因此也被改变
?>
自 PHP 5 起,new 运算符自动返回一个引用,因此再对 new 的结果进行引用赋值在 PHP 5.3 以及以后版本中会发出一条 E_DEPRECATED 错误信息,在之前版本会发出一条 E_STRICT 错误信息。
例如以下代码将产生警告:
<?php
class C {}
/* The following line generates the following error message:
* Deprecated: Assigning the return value of new by reference is deprecated in...
*/
$o = &new C ;
?>
有关引用更多信息参见本手册中引用的解释一章。
(四)位运算符
位运算符允许对整型数中指定的位进行求值和操作。
- 位运算符
例子 | 名称 | 结果 |
---|---|---|
$a&$b |
And(按位与) | 将把 $a和$b中都为 1 的位设为 1。 |
$a|$b |
Or(按位或) | 将把 $a和$b中任何一个为 1 的位设为 1。 |
$a ^ $b |
Xor(按位异或) | 将把 $a和$b中一个为 1 另一个为 0 的位设为 1。 |
~ $a |
Not(按位取反) | 将 $a中为 0 的位设为 1,反之亦然。 |
$a << $b |
Shift left(左移) | 将 $a中的位向左移动 $b次(每一次移动都表示“乘以 2”)。 |
$a >> $b |
Shift right(右移) | 将 $a中的位向右移动 $b次(每一次移动都表示“除以 2”)。 |
位移在 PHP 中是数学运算。向任何方向移出去的位都被丢弃。左移时右侧以零填充,符号位被移走意味着正负号不被保留。右移时左侧以符号位填充,意味着正负号被保留。
要用括号确保想要的优先级。例如 $a & $b == true 先进行比较再进行按位与;而 ($a & $b) == true 则先进行按位与再进行比较。
要注意数据类型的转换。如果左右参数都是字符串,则位运算符将对字符的 ASCII 值进行操作。
PHP 的 ini 设定 error_reporting 使用了按位的值,
提供了关闭某个位的真实例子。要显示除了提示级别
之外的所有错误,php.ini 中是这样用的:
E_ALL & ~E_NOTICE
具体运作方式是先取得 E_ALL 的值:
00000000000000000111011111111111
再取得 E_NOTICE 的值:
00000000000000000000000000001000
然后通过 ~ 将其取反:
11111111111111111111111111110111
最后再用按位与 AND(&)得到两个值中都设定了(为 1)的位:
00000000000000000111011111110111
另外一个方法是用按位异或 XOR(^)来取得只在
其中一个值中设定了的位:
E_ALL ^ E_NOTICE
error_reporting 也可用来演示怎样置位。只显示错误和可恢复
错误的方法是:
E_ERROR | E_RECOVERABLE_ERROR
也就是将 E_ERROR
00000000000000000000000000000001
和 E_RECOVERABLE_ERROR
00000000000000000001000000000000
用按位或 OR(|)运算符来取得在任何一个值中被置位的结果:
00000000000000000001000000000001
Example #1 整数的 AND,OR 和 XOR 位运算符
<?php
/*
* Ignore the top section,
* it is just formatting to make output clearer.
*/
$format = '(%1$2d = %1$04b) = (%2$2d = %2$04b)'
. ' %3$s (%4$2d = %4$04b)' . "\n" ;
echo <<<EOH
--------- --------- -- ---------
result value op test
--------- --------- -- ---------
EOH;
/*
* Here are the examples.
*/
$values = array( 0 , 1 , 2 , 4 , 8 );
$test = 1 + 4 ;
echo "\n Bitwise AND \n" ;
foreach ( $values as $value ) {
$result = $value & $test ;
printf ( $format , $result , $value , '&' , $test );
}
echo "\n Bitwise Inclusive OR \n" ;
foreach ( $values as $value ) {
$result = $value | $test ;
printf ( $format , $result , $value , '|' , $test );
}
echo "\n Bitwise Exclusive OR (XOR) \n" ;
foreach ( $values as $value ) {
$result = $value ^ $test ;
printf ( $format , $result , $value , '^' , $test );
}
?>
以上例程会输出:
--------- --------- -- ---------
result value op test
--------- --------- -- ---------
Bitwise AND
( 0 = 0000) = ( 0 = 0000) & ( 5 = 0101)
( 1 = 0001) = ( 1 = 0001) & ( 5 = 0101)
( 0 = 0000) = ( 2 = 0010) & ( 5 = 0101)
( 4 = 0100) = ( 4 = 0100) & ( 5 = 0101)
( 0 = 0000) = ( 8 = 1000) & ( 5 = 0101) Bitwise Inclusive OR
( 5 = 0101) = ( 0 = 0000) | ( 5 = 0101)
( 5 = 0101) = ( 1 = 0001) | ( 5 = 0101)
( 7 = 0111) = ( 2 = 0010) | ( 5 = 0101)
( 5 = 0101) = ( 4 = 0100) | ( 5 = 0101)
(13 = 1101) = ( 8 = 1000) | ( 5 = 0101) Bitwise Exclusive OR (XOR)
( 5 = 0101) = ( 0 = 0000) ^ ( 5 = 0101)
( 4 = 0100) = ( 1 = 0001) ^ ( 5 = 0101)
( 7 = 0111) = ( 2 = 0010) ^ ( 5 = 0101)
( 1 = 0001) = ( 4 = 0100) ^ ( 5 = 0101)
(13 = 1101) = ( 8 = 1000) ^ ( 5 = 0101)
Example #2 字符串的 XOR 运算符
<?php
echo 12 ^ 9 ; // Outputs '5'
echo "12" ^ "9" ; // Outputs the Backspace character (ascii 8)
// ('1' (ascii 49)) ^ ('9' (ascii 57)) = #8
echo "hallo" ^ "hello" ; // Outputs the ascii values #0 #4 #0 #0 #0
// 'a' ^ 'e' = #4
echo 2 ^ "3" ; // Outputs 1
// 2 ^ ((int)"3") == 1
echo "2" ^ 3 ; // Outputs 1
// ((int)"2") ^ 3 == 1
?>
Example #3 整数的位移
<?php
/*
* Here are the examples.
*/
echo "\n--- BIT SHIFT RIGHT ON POSITIVE INTEGERS ---\n" ;
$val = 4 ;
$places = 1 ;
$res = $val >> $places ;
p ( $res , $val , '>>' , $places , 'copy of sign bit shifted into left side' );
$val = 4 ;
$places = 2 ;
$res = $val >> $places ;
p ( $res , $val , '>>' , $places );
$val = 4 ;
$places = 3 ;
$res = $val >> $places ;
p ( $res , $val , '>>' , $places , 'bits shift out right side' );
$val = 4 ;
$places = 4 ;
$res = $val >> $places ;
p ( $res , $val , '>>' , $places , 'same result as above; can not shift beyond 0' );
echo "\n--- BIT SHIFT RIGHT ON NEGATIVE INTEGERS ---\n" ;
$val = - 4 ;
$places = 1 ;
$res = $val >> $places ;
p ( $res , $val , '>>' , $places , 'copy of sign bit shifted into left side' );
$val = - 4 ;
$places = 2 ;
$res = $val >> $places ;
p ( $res , $val , '>>' , $places , 'bits shift out right side' );
$val = - 4 ;
$places = 3 ;
$res = $val >> $places ;
p ( $res , $val , '>>' , $places , 'same result as above; can not shift beyond -1' );
echo "\n--- BIT SHIFT LEFT ON POSITIVE INTEGERS ---\n" ;
$val = 4 ;
$places = 1 ;
$res = $val << $places ;
p ( $res , $val , '<<' , $places , 'zeros fill in right side' );
$val = 4 ;
$places = ( PHP_INT_SIZE * 8 ) - 4 ;
$res = $val << $places ;
p ( $res , $val , '<<' , $places );
$val = 4 ;
$places = ( PHP_INT_SIZE * 8 ) - 3 ;
$res = $val << $places ;
p ( $res , $val , '<<' , $places , 'sign bits get shifted out' );
$val = 4 ;
$places = ( PHP_INT_SIZE * 8 ) - 2 ;
$res = $val << $places ;
p ( $res , $val , '<<' , $places , 'bits shift out left side' );
echo "\n--- BIT SHIFT LEFT ON NEGATIVE INTEGERS ---\n" ;
$val = - 4 ;
$places = 1 ;
$res = $val << $places ;
p ( $res , $val , '<<' , $places , 'zeros fill in right side' );
$val = - 4 ;
$places = ( PHP_INT_SIZE * 8 ) - 3 ;
$res = $val << $places ;
p ( $res , $val , '<<' , $places );
$val = - 4 ;
$places = ( PHP_INT_SIZE * 8 ) - 2 ;
$res = $val << $places ;
p ( $res , $val , '<<' , $places , 'bits shift out left side, including sign bit' );
/*
* Ignore this bottom section,
* it is just formatting to make output clearer.
*/
function p ( $res , $val , $op , $places , $note = '' ) {
$format = '%0' . ( PHP_INT_SIZE * 8 ) . "b\n" ;
printf ( "Expression: %d = %d %s %d\n" , $res , $val , $op , $places );
echo " Decimal:\n" ;
printf ( " val=%d\n" , $val );
printf ( " res=%d\n" , $res );
echo " Binary:\n" ;
printf ( ' val=' . $format , $val );
printf ( ' res=' . $format , $res );
if ( $note ) {
echo " NOTE: $note \n" ;
}
echo "\n" ;
}
?>
以上例程在 32 位机器上的输出:
--- BIT SHIFT RIGHT ON POSITIVE INTEGERS ---
Expression: 2 = 4 >> 1
Decimal:
val=4
res=2
Binary:
val=00000000000000000000000000000100
res=00000000000000000000000000000010
NOTE: copy of sign bit shifted into left sideExpression: 1 = 4 >> 2
Decimal:
val=4
res=1
Binary:
val=00000000000000000000000000000100
res=00000000000000000000000000000001Expression: 0 = 4 >> 3
Decimal:
val=4
res=0
Binary:
val=00000000000000000000000000000100
res=00000000000000000000000000000000
NOTE: bits shift out right sideExpression: 0 = 4 >> 4
Decimal:
val=4
res=0
Binary:
val=00000000000000000000000000000100
res=00000000000000000000000000000000
NOTE: same result as above; can not shift beyond 0--- BIT SHIFT RIGHT ON NEGATIVE INTEGERS ---
Expression: -2 = -4 >> 1
Decimal:
val=-4
res=-2
Binary:
val=11111111111111111111111111111100
res=11111111111111111111111111111110
NOTE: copy of sign bit shifted into left sideExpression: -1 = -4 >> 2
Decimal:
val=-4
res=-1
Binary:
val=11111111111111111111111111111100
res=11111111111111111111111111111111
NOTE: bits shift out right sideExpression: -1 = -4 >> 3
Decimal:
val=-4
res=-1
Binary:
val=11111111111111111111111111111100
res=11111111111111111111111111111111
NOTE: same result as above; can not shift beyond -1--- BIT SHIFT LEFT ON POSITIVE INTEGERS ---
Expression: 8 = 4 << 1
Decimal:
val=4
res=8
Binary:
val=00000000000000000000000000000100
res=00000000000000000000000000001000
NOTE: zeros fill in right sideExpression: 1073741824 = 4 << 28
Decimal:
val=4
res=1073741824
Binary:
val=00000000000000000000000000000100
res=01000000000000000000000000000000Expression: -2147483648 = 4 << 29
Decimal:
val=4
res=-2147483648
Binary:
val=00000000000000000000000000000100
res=10000000000000000000000000000000
NOTE: sign bits get shifted outExpression: 0 = 4 << 30
Decimal:
val=4
res=0
Binary:
val=00000000000000000000000000000100
res=00000000000000000000000000000000
NOTE: bits shift out left side--- BIT SHIFT LEFT ON NEGATIVE INTEGERS ---
Expression: -8 = -4 << 1
Decimal:
val=-4
res=-8
Binary:
val=11111111111111111111111111111100
res=11111111111111111111111111111000
NOTE: zeros fill in right sideExpression: -2147483648 = -4 << 29
Decimal:
val=-4
res=-2147483648
Binary:
val=11111111111111111111111111111100
res=10000000000000000000000000000000Expression: 0 = -4 << 30
Decimal:
val=-4
res=0
Binary:
val=11111111111111111111111111111100
res=00000000000000000000000000000000
NOTE: bits shift out left side, including sign bit
以上例程在 64 位机器上的输出:
--- BIT SHIFT RIGHT ON POSITIVE INTEGERS ---
Expression: 2 = 4 >> 1
Decimal:
val=4
res=2
Binary:
val=0000000000000000000000000000000000000000000000000000000000000100
res=0000000000000000000000000000000000000000000000000000000000000010
NOTE: copy of sign bit shifted into left sideExpression: 1 = 4 >> 2
Decimal:
val=4
res=1
Binary:
val=0000000000000000000000000000000000000000000000000000000000000100
res=0000000000000000000000000000000000000000000000000000000000000001Expression: 0 = 4 >> 3
Decimal:
val=4
res=0
Binary:
val=0000000000000000000000000000000000000000000000000000000000000100
res=0000000000000000000000000000000000000000000000000000000000000000
NOTE: bits shift out right sideExpression: 0 = 4 >> 4
Decimal:
val=4
res=0
Binary:
val=0000000000000000000000000000000000000000000000000000000000000100
res=0000000000000000000000000000000000000000000000000000000000000000
NOTE: same result as above; can not shift beyond 0--- BIT SHIFT RIGHT ON NEGATIVE INTEGERS ---
Expression: -2 = -4 >> 1
Decimal:
val=-4
res=-2
Binary:
val=1111111111111111111111111111111111111111111111111111111111111100
res=1111111111111111111111111111111111111111111111111111111111111110
NOTE: copy of sign bit shifted into left sideExpression: -1 = -4 >> 2
Decimal:
val=-4
res=-1
Binary:
val=1111111111111111111111111111111111111111111111111111111111111100
res=1111111111111111111111111111111111111111111111111111111111111111
NOTE: bits shift out right sideExpression: -1 = -4 >> 3
Decimal:
val=-4
res=-1
Binary:
val=1111111111111111111111111111111111111111111111111111111111111100
res=1111111111111111111111111111111111111111111111111111111111111111
NOTE: same result as above; can not shift beyond -1--- BIT SHIFT LEFT ON POSITIVE INTEGERS ---
Expression: 8 = 4 << 1
Decimal:
val=4
res=8
Binary:
val=0000000000000000000000000000000000000000000000000000000000000100
res=0000000000000000000000000000000000000000000000000000000000001000
NOTE: zeros fill in right sideExpression: 4611686018427387904 = 4 << 60
Decimal:
val=4
res=4611686018427387904
Binary:
val=0000000000000000000000000000000000000000000000000000000000000100
res=0100000000000000000000000000000000000000000000000000000000000000Expression: -9223372036854775808 = 4 << 61
Decimal:
val=4
res=-9223372036854775808
Binary:
val=0000000000000000000000000000000000000000000000000000000000000100
res=1000000000000000000000000000000000000000000000000000000000000000
NOTE: sign bits get shifted outExpression: 0 = 4 << 62
Decimal:
val=4
res=0
Binary:
val=0000000000000000000000000000000000000000000000000000000000000100
res=0000000000000000000000000000000000000000000000000000000000000000
NOTE: bits shift out left side--- BIT SHIFT LEFT ON NEGATIVE INTEGERS ---
Expression: -8 = -4 << 1
Decimal:
val=-4
res=-8
Binary:
val=1111111111111111111111111111111111111111111111111111111111111100
res=1111111111111111111111111111111111111111111111111111111111111000
NOTE: zeros fill in right sideExpression: -9223372036854775808 = -4 << 61
Decimal:
val=-4
res=-9223372036854775808
Binary:
val=1111111111111111111111111111111111111111111111111111111111111100
res=1000000000000000000000000000000000000000000000000000000000000000Expression: 0 = -4 << 62
Decimal:
val=-4
res=0
Binary:
val=1111111111111111111111111111111111111111111111111111111111111100
res=0000000000000000000000000000000000000000000000000000000000000000
NOTE: bits shift out left side, including sign bit
Warning
不要在 32 位系统下向右移超过 32 位。不要在结果可能超过 32 的情况下左移。使用 gmp 扩展对超出 PHP_INT_MAX 的数值来进行位操作。
参见 pack() , unpack() , gmp_and() , gmp_or() , gmp_xor() , gmp_testbit() 和 gmp_clrbit() 。
(五)比较运算符
比较运算符,如同它们名称所暗示的,允许对两个值进行比较。还可以参考 PHP 类型比较表看不同类型相互比较的例子。
比较运算符
例子 | 名称 | 结果 |
---|---|---|
$a==$b | 等于 | TRUE,如果类型转换后$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,如果$a严格小于$b。 |
$a>$b | 大于 | TRUE,如果$a严格大于$b。 |
$a<=$b | 小于等于 | TRUE,如果$a小于或者等于$b。 |
$a>=$b | 大于等于 | TRUE,如果 $a大于或者等于$b。 |
如果比较一个数字和字符串或者比较涉及到数字内容的字符串,则字符串会被转换为数值并且比较按照数值来进行。此规则也适用于 switch 语句。当用 === 或 !== 进行比较时则不进行类型转换,因为此时类型和数值都要比对。
<?php
var_dump ( 0 == "a" ); // 0 == 0 -> true
var_dump ( "1" == "01" ); // 1 == 1 -> true
var_dump ( "10" == "1e1" ); // 10 == 10 -> true
var_dump ( 100 == "1e2" ); // 100 == 100 -> true
switch ( "a" ) {
case 0 :
echo "0" ;
break;
case "a" : // never reached because "a" is already matched with 0
echo "a" ;
break;
}
?>
对于多种类型,比较运算符根据下表比较(按顺序)。
- 比较多种类型
运算数1类型 | 运算数2类型 | 结果 |
---|---|---|
null或string | string | 将 NULL转换为 "",进行数字或词汇比较 |
bool或null | 任何其它类型 | 转换为 bool,FALSE<TRUE |
object | object | 内置类可以定义自己的比较,不同类不能比较,相同类和数组同样方式比较属性(PHP 4 中),PHP 5 有其自己的说明 |
string,resource或number | string,resource或number | 将字符串和资源转换成数字,按普通数学比较 |
array | array | 具有较少成员的数组较小,如果运算数1中的键不存在于运算数2中则数组无法比较,否则挨个值比较(见下例) |
object | 任何其它类型 | object总是更大 |
array | 任何其它类型 | array总是更大 |
Example #1 标准数组比较代码
<?php
// 数组是用标准比较运算符这样比较的
function standard_array_compare ( $op1 , $op2 )
{
if ( count ( $op1 ) < count ( $op2 )) {
return - 1 ; // $op1 < $op2
} elseif ( count ( $op1 ) > count ( $op2 )) {
return 1 ; // $op1 > $op2
}
foreach ( $op1 as $key => $val ) {
if (! array_key_exists ( $key , $op2 )) {
return null ; // uncomparable
} elseif ( $val < $op2 [ $key ]) {
return - 1 ;
} elseif ( $val > $op2 [ $key ]) {
return 1 ;
}
}
return 0 ; // $op1 == $op2
}
?>
参见 strcasecmp() , strcmp() ,数组运算符和类型章节。
- Warning
比较浮点数:由于浮点数 float 的内部表达方式,不应比较两个浮点数是否相等。
更多信息参见 float 。
- 三元运算符
另一个条件运算符是“?:”(或三元)运算符 。
Example #2 赋默认值
<?php
// Example usage for: Ternary Operator
$action = (empty( $_POST [ 'action' ])) ? 'default' : $_POST [ 'action' ];
// The above is identical to this if/else statement
if (empty( $_POST [ 'action' ])) {
$action = 'default' ;
} else {
$action = $_POST [ 'action' ];
}
?>
表达式 (expr1) ? (expr2) : (expr3) 在 expr1 求值为 TRUE 时的值为 expr2,在 expr1 求值为 FALSE 时的值为 expr3。
自 PHP 5.3 起,可以省略三元运算符中间那部分。表达式 expr1 ?: expr3 在 expr1 求值为 TRUE 时返回 expr1,否则返回 expr3。
-
Note: 注意三元运算符是个语句,因此其求值不是变量,而是语句的结果。如果想通过引用返回一个变量这点就很重要。在一个通过引用返回的函数中语句 return $var == 42 ? $a : $b; 将不起作用,以后的 PHP 版本会为此发出一条警告。
-
Note: 建议避免将三元运算符堆积在一起使用。当在一条语句中使用多个三元运算符时会造成 PHP 运算结果不清晰:
Example #3 不清晰的三元运算符行为
<?php
// 乍看起来下面的输出是 'true'
echo ( true ? 'true' : false ? 't' : 'f' );
// 然而,上面语句的实际输出是't',因为三元运算符是从左往右计算的
// 下面是与上面等价的语句,但更清晰
echo (( true ? 'true' : 'false' ) ? 't' : 'f' );
// here, you can see that the first expression is evaluated to 'true', which
// in turn evaluates to (bool)true, thus returning the true branch of the
// second ternary expression.
?>
(六)错误控制运算符
PHP 支持一个错误控制运算符:@。当将其放置在一个 PHP 表达式之前,该表达式可能产生的任何错误信息都被忽略掉。
如果用 set_error_handler() 设定了自定义的错误处理函数,仍然会被调用,但是此错误处理函数可以(并且也应该)调用 error_reporting() ,而该函数在出错语句前有 @ 时将返回 0。
如果激活了 track_errors 特性,表达式所产生的任何错误信息都被存放在变量 $php_errormsg 中。此变量在每次出错时都会被覆盖,所以如果想用它的话就要尽早检查。
<?php
/* Intentional file error */
$my_file = @ file ( 'non_existent_file' ) or
die ( "Failed opening file: error was ' $php_errormsg '" );
// this works for any expression, not just functions:
$value = @ $cache [ $key ];
// will not issue a notice if the index $key doesn't exist.
?>
- Note: @ 运算符只对表达式有效。对新手来说一个简单的规则就是:如果能从某处得到值,就能在它前面加上 @ 运算符。例如,可以把它放在变量,函数和 include 调用,常量,等等之前。不能把它放在函数或类的定义之前,也不能用于条件结构例如 if 和 foreach 等。
参见 error_reporting() 及手册中错误处理及日志函数的有关章节。
- Warning:目前的“@”错误控制运算符前缀甚至使导致脚本终止的严重错误的错误报告也失效。这意味着如果在某个不存在或者敲错了字母的函数调用前用了“@”来抑制错误信息,那脚本会没有任何迹象显示原因而死在那里。
(七)执行运算符
PHP 支持一个执行运算符:反引号(`)。注意这不是单引号!PHP 将尝试将反引号中的内容作为外壳命令来执行,并将其输出信息返回(即,可以赋给一个变量而不是简单地丢弃到标准输出)。使用反引号运算符“
”的效果与函数 shell_exec() 相同。
<?php
$output = ` ls -al `;
echo "<pre> $output </pre>" ;
?>
-
Note:反引号运算符在激活了安全模式或者关闭了 shell_exec() 时是无效的。
-
Note:与其它某些语言不同,反引号不能在双引号字符串中使用。
参见手册中程序执行函数, popen() , proc_open() 以及 PHP 的命令行模式。
(八)递增/递减运算符
PHP 支持 C 风格的前/后递增与递减运算符。
- Note: 递增/递减运算符不影响布尔值。递减 NULL值也没有效果,但是递增 NULL的结果是 1。
递增/递减运算符
例子 | 名称 | 效果 |
---|---|---|
++$a | 前加 | $a的值加一,然后返回$a。 |
$a++ | 后加 | 返回$a,然后将$a的值加一。 |
--$a | 前减 | $a的值减一,然后返回$a。 |
$a-- | 后减 | 返回$a,然后将$a的值减一。 |
一个简单的示例脚本:
<?php
echo "<h3>Postincrement</h3>" ;
$a = 5 ;
echo "Should be 5: " . $a ++ . "<br />\n" ;
echo "Should be 6: " . $a . "<br />\n" ;
echo "<h3>Preincrement</h3>" ;
$a = 5 ;
echo "Should be 6: " . ++ $a . "<br />\n" ;
echo "Should be 6: " . $a . "<br />\n" ;
echo "<h3>Postdecrement</h3>" ;
$a = 5 ;
echo "Should be 5: " . $a -- . "<br />\n" ;
echo "Should be 4: " . $a . "<br />\n" ;
echo "<h3>Predecrement</h3>" ;
$a = 5 ;
echo "Should be 4: " . -- $a . "<br />\n" ;
echo "Should be 4: " . $a . "<br />\n" ;
?>
在处理字符变量的算数运算时,PHP 沿袭了 Perl 的习惯,而非 C 的。例如,在 Perl 中 $a = 'Z'; $a++; 将把 $a 变成'AA',而在 C 中,a = 'Z'; a++; 将把 a 变成 '['('Z' 的 ASCII 值是 90,'[' 的 ASCII 值是 91)。注意字符变量只能递增,不能递减,并且只支持纯字母(a-z 和 A-Z)。递增/递减其他字符变量则无效,原字符串没有变化。
Example #1 涉及字符变量的算数运算
<?php
$i = 'W' ;
for ( $n = 0 ; $n < 6 ; $n ++) {
echo ++ $i . "\n" ;
}
?>
以上例程会输出:
X
Y
Z
AA
AB
AC
递增或递减布尔值没有效果。
(九)逻辑运算符
例子 | 名称 | 结果 |
---|---|---|
$a and $b | And(逻辑与) | TRUE,如果$a和$b都为TRUE。 |
$a or $b | Or(逻辑或) | TRUE,如果$a或$b任一为TRUE。 |
$a xor $b | Xor(逻辑异或) | TRUE,如果$a或$b任一为TRUE,但不同时是。 |
! $a | Not(逻辑非) | TRUE,如果$a不为TRUE。 |
$a && $b | And(逻辑与) | TRUE,如果$a和$b都为TRUE。 |
$a||$b |
Or(逻辑或) | TRUE,如果$a或$b任一为TRUE。 |
“与”和“或”有两种不同形式运算符的原因是它们运算的优先级不同(见运算符优先级)。
Example #1 逻辑运算符示例
<?php
// --------------------
// foo() 根本没机会被调用,被运算符“短路”了
$a = ( false && foo ());
$b = ( true || foo ());
$c = ( false and foo ());
$d = ( true or foo ());
// --------------------
// "||" 比 "or" 的优先级高
// 表达式 (false || true) 的结果被赋给 $e
// 等同于:($e = (false || true))
$e = false || true ;
// 常量 false 被赋给 $f,true 被忽略
// 等同于:(($f = false) or true)
$f = false or true ;
var_dump ( $e , $f );
// --------------------
// "&&" 比 "and" 的优先级高
// 表达式 (true && false) 的结果被赋给 $g
// 等同于:($g = (true && false))
$g = true && false ;
// 常量 true 被赋给 $h,false 被忽略
// 等同于:(($h = true) and false)
$h = true and false ;
var_dump ( $g , $h );
?>
以上例程的输出类似于:
bool(true)
bool(false)
bool(false)
bool(true)
(十)字符串运算符
有两个字符串( string )运算符。第一个是连接运算符(“.”),它返回其左右参数连接后的字符串。第二个是连接赋值运算符(“.=”),它将右边参数附加到左边的参数之后。更多信息见赋值运算符。
<?php
$a = "Hello " ;
$b = $a . "World!" ; // now $b contains "Hello World!"
$a = "Hello " ;
$a .= "World!" ; // now $a contains "Hello World!"
?>
参见字符串类型和字符串函数章节。
(十一)数组运算符
数组运算符
例子 | 名称 | 结果 |
---|---|---|
$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 。 |
- 运算符把右边的数组元素附加到左边的数组后面,两个数组中都有的键名,则只用左边数组中的,右边的被忽略。
<?php
$a = array( "a" => "apple" , "b" => "banana" );
$b = array( "a" => "pear" , "b" => "strawberry" , "c" => "cherry" );
$c = $a + $b ; // Union of $a and $b
echo "Union of \$a and \$b: \n" ;
var_dump ( $c );
$c = $b + $a ; // Union of $b and $a
echo "Union of \$b and \$a: \n" ;
var_dump ( $c );
?>
执行后,此脚本会显示:
Union of $a and $b:
array(3) {
["a"]=>
string(5) "apple"
["b"]=>
string(6) "banana"
["c"]=>
string(6) "cherry"
}
Union of $b and $a:
array(3) {
["a"]=>
string(4) "pear"
["b"]=>
string(10) "strawberry"
["c"]=>
string(6) "cherry"
}
数组中的单元如果具有相同的键名和值则比较时相等。
Example #1 比较数组
<?php
$a = array( "apple" , "banana" );
$b = array( 1 => "banana" , "0" => "apple" );
var_dump ( $a == $b ); // bool(true)
var_dump ( $a === $b ); // bool(false)
?>
参见数组类型和数组函数章节。
(十二)类型运算符
instanceof 用于确定一个 PHP 变量是否属于某一类 class 的实例:
Example #1 对类使用 instanceof
<?php
class MyClass
{
}
class NotMyClass
{
}
$a = new MyClass ;
var_dump ( $a instanceof MyClass );
var_dump ( $a instanceof NotMyClass );
?>
以上例程会输出:
bool(true)
bool(false)
instanceof 也可用来确定一个变量是不是继承自某一父类的子类的实例:
Example #2 对继承类使用 instanceof
<?php
class ParentClass
{
}
class MyClass extends ParentClass
{
}
$a = new MyClass ;
var_dump ( $a instanceof MyClass );
var_dump ( $a instanceof ParentClass );
?>
以上例程会输出:
bool(true)
bool(true)
检查一个对象是否不是某个类的实例,可以使用逻辑运算符 not 。
Example #3 使用 instanceof 检查对象不是某个类的实例
<?php
class MyClass
{
}
$a = new MyClass ;
var_dump (!( $a instanceof stdClass ));
?>
以上例程会输出:
bool(true)
最后,instanceof也可用于确定一个变量是不是实现了某个接口的对象的实例:
Example #4 对接口使用 instanceof
<?php
interface MyInterface
{
}
class MyClass implements MyInterface
{
}
$a = new MyClass ;
var_dump ( $a instanceof MyClass );
var_dump ( $a instanceof MyInterface );
?>
以上例程会输出:
bool(true)
bool(true)
虽然 instanceof 通常直接与类名一起使用,但也可以使用对象或字符串变量:
Example #5 对其它变量使用 instanceof
<?php
interface MyInterface
{
}
class MyClass implements MyInterface
{
}
$a = new MyClass ;
$b = new MyClass ;
$c = 'MyClass' ;
$d = 'NotMyClass' ;
var_dump ( $a instanceof $b ); // $b is an object of class MyClass
var_dump ( $a instanceof $c ); // $c is a string 'MyClass'
var_dump ( $a instanceof $d ); // $d is a string 'NotMyClass'
?>
以上例程会输出:
bool(true)
bool(true)
bool(false)
如果被检测的变量不是对象,instanceof 并不发出任何错误信息而是返回 FALSE 。不允许用来检测常量。
Example #6 用 instanceof 检测其它变量
<?php
$a = 1 ;
$b = NULL ;
$c = imagecreate ( 5 , 5 );
var_dump ( $a instanceof stdClass ); // $a is an integer
var_dump ( $b instanceof stdClass ); // $b is NULL
var_dump ( $c instanceof stdClass ); // $c is a resource
var_dump ( FALSE instanceof stdClass );
?>
以上例程会输出:
bool(false)
bool(false)
bool(false)
PHP Fatal error: instanceof expects an object instance, constant given
然而 instanceof 的使用还有一些陷阱必须了解。在 PHP 5.1.0 之前,如果要检查的类名称不存在,instanceof 会调用 __autoload() 。另外,如果该类没有被装载则会产生一个致命错误。可以通过使用动态类引用或用一个包含类名的字符串变量来避开这种问题:
Example #7 避免 PHP 5.0 中 instanceof 引起的类名查找和致命错误问题
<?php
$d = 'NotMyClass' ;
var_dump ( $a instanceof $d ); // no fatal error here
?>
以上例程会输出:
bool(false)
instanceof 运算符是 PHP 5 引进的。在此之前用 is_a() ,但是后来 is_a() 被废弃而用 instanceof 替代了。注意自 PHP 5.3.0 起,又恢复使用 is_a() 了。
参见 get_class() 和 is_a() 。
七、流程控制
(一)简介
任何 PHP 脚本都是由一系列语句构成的。一条语句可以是一个赋值语句,一个函数调用,一个循环,一个条件语句或者甚至是一个什么也不做的语句(空语句)。语句通常以分号结束。此外,还可以用花括号将一组语句封装成一个语句组。语句组本身可以当作是一行语句。本章介绍了各种语句类型。
(二)if
(PHP 4, PHP 5)
if 结构是很多语言包括 PHP 在内最重要的特性之一,它允许按照条件执行代码片段。PHP 的 if 结构和 C 语言相似:
<?php
if (expr)
statement
?>
如同在表达式一章中定义的,expr 按照布尔求值。如果 expr 的值为 TRUE ,PHP 将执行 statement,如果值为 FALSE ——将忽略 statement。有关哪些值被视为 FALSE 的更多信息参见转换为布尔值一节。
如果 $a 大于 $b ,则以下例子将显示 a is bigger than b:
<?php
if ( $a > $b )
echo "a is bigger than b" ;
?>
经常需要按照条件执行不止一条语句,当然并不需要给每条语句都加上一个 if 子句。可以将这些语句放入语句组中。例如,如果 $a 大于 $b ,以下代码将显示 a is bigger than b 并且将 $a 的值赋给 $b :
<?php
if ( $a > $b ) {
echo "a is bigger than b" ;
$b = $a ;
}
?>
if 语句可以无限层地嵌套在其它 if 语句中,这给程序的不同部分的条件执行提供了充分的弹性。
(三)else
(PHP 4, PHP 5)
经常需要在满足某个条件时执行一条语句,而在不满足该条件时执行其它语句,这正是 else 的功能。else 延伸了 if 语句,可以在 if 语句中的表达式的值为 FALSE 时执行语句。例如以下代码在 $a 大于 $b 时显示 a is bigger than b,反之则显示 a is NOT bigger than b:
<?php
if ( $a > $b ) {
echo "a is greater than b" ;
} else {
echo "a is NOT greater than b" ;
}
?>
else 语句仅在 if 以及 elseif(如果有的话)语句中的表达式的值为 FALSE 时执行(参见 elseif)。
(四)elseif/else if
(PHP 4, PHP 5)
elseif,和此名称暗示的一样,是 if 和 else 的组合。和 else 一样,它延伸了 if 语句,可以在原来的 if 表达式值为 FALSE 时执行不同语句。但是和 else 不一样的是,它仅在 elseif 的条件表达式值为 TRUE 时执行语句。例如以下代码将根据条件分别显示 a is bigger than b,a equal to b 或者 a is smaller than b:
<?php
if ( $a > $b ) {
echo "a is bigger than b" ;
} elseif ( $a == $b ) {
echo "a is equal to b" ;
} else {
echo "a is smaller than b" ;
}
?>
在同一个 if 语句中可以有多个 elseif 部分,其中第一个表达式值为 TRUE (如果有的话)的 elseif 部分将会执行。在 PHP 中,也可以写成“else if”(两个单词),它和“elseif”(一个单词)的行为完全一样。句法分析的含义有少许区别(如果你熟悉 C 语言的话,与之行为相同),但是底线是两者会产生完全一样的行为。
elseif 的语句仅在之前的 if 和所有之前 elseif 的表达式值为 FALSE ,并且当前的 elseif 表达式值为 TRUE 时执行。
- Note: 必须要注意的是 elseif 与 else if 只有在类似上例中使用花括号的情况下才认为是完全相同。如果用冒号来定义 if/elseif 条件,那就不能用两个单词的 else if,否则 PHP 会产生解析错误。
<?php
/* 不正确的使用方法: */
if( $a > $b ):
echo $a . " is greater than " . $b ;
else if( $a == $b ): // 将无法编译
echo "The above line causes a parse error." ;
endif;
/* 正确的使用方法: */
if( $a > $b ):
echo $a . " is greater than " . $b ;
elseif( $a == $b ): // 注意使用了一个单词的 elseif
echo $a . " equals " . $b ;
else:
echo $a . " is neither greater than or equal to " . $b ;
endif;
?>
(五)流程控制的替代语法
(PHP 4, PHP 5)
PHP 提供了一些流程控制的替代语法,包括 if,while,for,foreach 和 switch。替代语法的基本形式是把左花括号({)换成冒号(:),把右花括号(})分别换成 endif;,endwhile;,endfor;,endforeach; 以及 endswitch;。
<?php if ( $a == 5 ): ?>
A is equal to 5
<?php endif; ?>
在上面的例子中,HTML 内容“A is equal to 5”用替代语法嵌套在 if 语句中。该 HTML 的内容仅在 $a 等于 5 时显示。
替代语法同样可以用在 else 和 elseif 中。下面是一个包括 elseif 和 else 的 if 结构用替代语法格式写的例子:
<?php
if ( $a == 5 ):
echo "a equals 5" ;
echo "..." ;
elseif ( $a == 6 ):
echo "a equals 6" ;
echo "!!!" ;
else:
echo "a is neither 5 nor 6" ;
endif;
?>
- Note: 不支持在同一个控制块内混合使用两种语法。
更多例子参见 while,for 和 if。
(六)while
(PHP 4, PHP 5)
while 循环是 PHP 中最简单的循环类型。它和 C 语言中的 while 表现地一样。while 语句的基本格式是:
while (expr)
statement
while 语句的含意很简单,它告诉 PHP 只要 while 表达式的值为 TRUE 就重复执行嵌套中的循环语句。表达式的值在每次开始循环时检查,所以即使这个值在循环语句中改变了,语句也不会停止执行,直到本次循环结束。有时候如果 while 表达式的值一开始就是 FALSE ,则循环语句一次都不会执行。
和 if 语句一样,可以在 while 循环中用花括号括起一个语句组,或者用替代语法:
while (expr):
statement
...
endwhile;
下面两个例子完全一样,都显示数字 1 到 10:
<?php
/* example 1 */
$i = 1 ;
while ( $i <= 10 ) {
echo $i ++; /* the printed value would be
$i before the increment
(post-increment) */
}
/* example 2 */
$i = 1 ;
while ( $i <= 10 ):
print $i ;
$i ++;
endwhile;
?>
(七)do-while
(PHP 4, PHP 5)
do-while 循环和 while 循环非常相似,区别在于表达式的值是在每次循环结束时检查而不是开始时。和一般的 while 循环主要的区别是 do-while 的循环语句保证会执行一次(表达式的真值在每次循环结束后检查),然而在一般的 while 循环中就不一定了(表达式真值在循环开始时检查,如果一开始就为 FALSE 则整个循环立即终止)。
do-while 循环只有一种语法:
<?php
$i = 0 ;
do {
echo $i ;
} while ( $i > 0 );
?>
以上循环将正好运行一次,因为经过第一次循环后,当检查表达式的真值时,其值为 FALSE ( $i 不大于 0)而导致循环终止。
资深的 C 语言用户可能熟悉另一种不同的 do-while 循环用法,把语句放在 do-while(0) 之中,在循环内部用 break 语句来结束执行循环。以下代码片段示范了此方法:
<?php
do {
if ( $i < 5 ) {
echo "i is not big enough" ;
break;
}
$i *= $factor ;
if ( $i < $minimum_limit ) {
break;
}
echo "i is ok" ;
/* process i */
} while( 0 );
?>
如果还不能立刻理解也不用担心。即使不用此“特性”也照样可以写出强大的代码来。自 PHP 5.3.0 起,还可以使用 goto 来跳出循环。
(八)for
(PHP 4, PHP 5)
for 循环是 PHP 中最复杂的循环结构。它的行为和 C 语言的相似。 for 循环的语法是:
for (expr1; expr2; expr3)
statement
第一个表达式( expr1 )在循环开始前无条件求值(并执行)一次。
expr2 在每次循环开始前求值。如果值为 TRUE ,则继续循环,执行嵌套的循环语句。如果值为 FALSE ,则终止循环。
expr3 在每次循环之后被求值(并执行)。
每个表达式都可以为空或包括逗号分隔的多个表达式。表达式 expr2 中,所有用逗号分隔的表达式都会计算,但只取最后一个结果。 expr2 为空意味着将无限循环下去(和 C 一样,PHP 暗中认为其值为 TRUE )。这可能不像想象中那样没有用,因为经常会希望用有条件的 break 语句来结束循环而不是用 for 的表达式真值判断。
考虑以下的例子,它们都显示数字 1 到 10:
<?php
/* example 1 */
for ( $i = 1 ; $i <= 10 ; $i ++) {
echo $i ;
}
/* example 2 */
for ( $i = 1 ; ; $i ++) {
if ( $i > 10 ) {
break;
}
echo $i ;
}
/* example 3 */
$i = 1 ;
for (;;) {
if ( $i > 10 ) {
break;
}
echo $i ;
$i ++;
}
/* example 4 */
for ( $i = 1 , $j = 0 ; $i <= 10 ; $j += $i , print $i , $i ++);
?>
当然,第一个例子看上去最简洁(或者有人认为是第四个),但用户可能会发现在 for 循环中用空的表达式在很多场合下会很方便。
PHP 也支持用冒号的 for 循环的替代语法。
for (expr1; expr2; expr3):
statement;
...
endfor;
有时经常需要像下面这样例子一样对数组进行遍历:
<?php
/*
* 此数组将在遍历的过程中改变其中某些单元的值
*/
$people = Array(
Array( 'name' => 'Kalle' , 'salt' => 856412 ),
Array( 'name' => 'Pierre' , 'salt' => 215863 )
);
for( $i = 0 ; $i < count ( $people ); ++ $i )
{
$people [ $i ][ 'salt' ] = rand ( 000000 , 999999 );
}
?>
以上代码可能执行很慢,因为每次循环时都要计算一遍数组的长度。由于数组的长度始终不变,可以用一个中间变量来储存数组长度以优化而不是不停调用 count() :
<?php
$people = Array(
Array( 'name' => 'Kalle' , 'salt' => 856412 ),
Array( 'name' => 'Pierre' , 'salt' => 215863 )
);
for( $i = 0 , $size = count ( $people ); $i < $size ; ++ $i )
{
$people [ $i ][ 'salt' ] = rand ( 000000 , 999999 );
}
?>
(九)foreach
(PHP 4, PHP 5)
foreach 语法结构提供了遍历数组的简单方式。foreach 仅能够应用于数组和对象,如果尝试应用于其他数据类型的变量,或者未初始化的变量将发出错误信息。有两种语法:
foreach (array_expression as $value)
statement
foreach (array_expression as $key => $value)
statement
第一种格式遍历给定的 array_expression 数组。每次循环中,当前单元的值被赋给 $value 并且数组内部的指针向前移一步(因此下一次循环中将会得到下一个单元)。
第二种格式做同样的事,只除了当前单元的键名也会在每次循环中被赋给变量 $key。
还能够自定义遍历对象。
- Note:当 foreach 开始执行时,数组内部的指针会自动指向第一个单元。这意味着不需要在 foreach 循环之前调用 reset() 。
由于 foreach 依赖内部数组指针,在循环中修改其值将可能导致意外的行为。
可以很容易地通过在 $value 之前加上 &
来修改数组的元素。此方法将以引用赋值而不是拷贝一个值。
<?php
$arr = array( 1 , 2 , 3 , 4 );
foreach ( $arr as & $value ) {
$value = $value * 2 ;
}
// $arr is now array(2, 4, 6, 8)
unset( $value ); // 最后取消掉引用
?>
$value 的引用仅在被遍历的数组可以被引用时才可用(例如是个变量)。以下代码则无法运行:
<?php
foreach (array( 1 , 2 , 3 , 4 ) as & $value ) {
$value = $value * 2 ;
}
?>
- Warning:数组最后一个元素的 $value 引用在 foreach 循环之后仍会保留。建议使用 unset() 来将其销毁。
- Note: foreach 不支持用“@”来抑制错误信息的能力。
用户可能注意到了以下的代码功能完全相同:
<?php
$arr = array( "one" , "two" , "three" );
reset ( $arr );
while (list(, $value ) = each ( $arr )) {
echo "Value: $value <br>\n" ;
}
foreach ( $arr as $value ) {
echo "Value: $value <br />\n" ;
}
?>
以下代码功能也完全相同:
<?php
$arr = array( "one" , "two" , "three" );
reset ( $arr );
while (list( $key , $value ) = each ( $arr )) {
echo "Key: $key ; Value: $value <br />\n" ;
}
foreach ( $arr as $key => $value ) {
echo "Key: $key ; Value: $value <br />\n" ;
}
?>
示范用法的更多例子:
<?php
/* foreach example 1: value only */
$a = array( 1 , 2 , 3 , 17 );
foreach ( $a as $v ) {
echo "Current value of \$a: $v .\n" ;
}
/* foreach example 2: value (with its manual access notation printed for illustration) */
$a = array( 1 , 2 , 3 , 17 );
$i = 0 ; /* for illustrative purposes only */
foreach ( $a as $v ) {
echo "\$a[ $i ] => $v .\n" ;
$i ++;
}
/* foreach example 3: key and value */
$a = array(
"one" => 1 ,
"two" => 2 ,
"three" => 3 ,
"seventeen" => 17
);
foreach ( $a as $k => $v ) {
echo "\$a[ $k ] => $v .\n" ;
}
/* foreach example 4: multi-dimensional arrays */
$a = array();
$a [ 0 ][ 0 ] = "a" ;
$a [ 0 ][ 1 ] = "b" ;
$a [ 1 ][ 0 ] = "y" ;
$a [ 1 ][ 1 ] = "z" ;
foreach ( $a as $v1 ) {
foreach ( $v1 as $v2 ) {
echo " $v2 \n" ;
}
}
/* foreach example 5: dynamic arrays */
foreach (array( 1 , 2 , 3 , 4 , 5 ) as $v ) {
echo " $v \n" ;
}
?>
用 list() 给嵌套的数组解包
(PHP 5 >= 5.5.0)
PHP 5.5 增添了遍历一个数组的数组的功能并且把嵌套的数组解包到循环变量中,只需将 list() 作为值提供。
例如:
<?php
$array = [
[ 1 , 2 ],
[ 3 , 4 ],
];
foreach ( $array as list( $a , $b )) {
// $a contains the first element of the nested array,
// and $b contains the second element.
echo "A: $a ; B: $b \n" ;
}
?>
以上例程会输出:
A: 1; B: 2
A: 3; B: 4
list() 中的单元可以少于嵌套数组的,此时多出来的数组单元将被忽略:
<?php
$array = [
[ 1 , 2 ],
[ 3 , 4 ],
];
foreach ( $array as list( $a )) {
// Note that there is no $b here.
echo " $a \n" ;
}
?>
以上例程会输出:
1
3
如果 list() 中列出的单元多于嵌套数组则会发出一条消息级别的错误信息:
<?php
$array = [
[ 1 , 2 ],
[ 3 , 4 ],
];
foreach ( $array as list( $a , $b , $c )) {
echo "A: $a ; B: $b ; C: $c \n" ;
}
?>
以上例程会输出:
Notice: Undefined offset: 2 in example.php on line 7
A: 1; B: 2; C: Notice: Undefined offset: 2 in example.php on line 7
A: 3; B: 4; C:
(十)break
(PHP 4, PHP 5)
break 结束当前 for,foreach,while,do-while 或者 switch 结构的执行。
break 可以接受一个可选的数字参数来决定跳出几重循环。
<?php
$arr = array( 'one' , 'two' , 'three' , 'four' , 'stop' , 'five' );
while (list (, $val ) = each ( $arr )) {
if ( $val == 'stop' ) {
break; /* You could also write 'break 1;' here. */
}
echo " $val <br />\n" ;
}
/* 使用可选参数 */
$i = 0 ;
while (++ $i ) {
switch ( $i ) {
case 5 :
echo "At 5<br />\n" ;
break 1 ; /* 只退出 switch. */
case 10 :
echo "At 10; quitting<br />\n" ;
break 2 ; /* 退出 switch 和 while 循环 */
default:
break;
}
}
?>
break 的更新记录
版本 | 说明 |
---|---|
5.4.0 | break 0; 不再合法。这在之前的版本被解析为 break 1;。 |
5.4.0 | 取消变量作为参数传递(例如 $num = 2; break $num;)。 |
(十一)continue
(PHP 4, PHP 5)
continue 在循环结构用用来跳过本次循环中剩余的代码并在条件求值为真时开始执行下一次循环。
Note: 注意在 PHP 中 switch 语句被认为是可以使用 continue 的一种循环结构。
continue 接受一个可选的数字参数来决定跳过几重循环到循环结尾。默认值是 1,即跳到当前循环末尾。
<?php
while (list ( $key , $value ) = each ( $arr )) {
if (!( $key % 2 )) { // skip odd members
continue;
}
do_something_odd ( $value );
}
$i = 0 ;
while ( $i ++ < 5 ) {
echo "Outer<br />\n" ;
while ( 1 ) {
echo "Middle<br />\n" ;
while ( 1 ) {
echo "Inner<br />\n" ;
continue 3 ;
}
echo "This never gets output.<br />\n" ;
}
echo "Neither does this.<br />\n" ;
}
?>
省略 continue 后面的分号会导致混淆。以下例子示意了不应该这样做。
<?php
for ( $i = 0 ; $i < 5 ; ++ $i ) {
if ( $i == 2 )
continue
print " $i \n" ;
}
?>
希望得到的结果是:
0
1
3
4
可实际的输出是:
2
因为整个 continue print "$i\n"; 被当做单一的表达式而求值,所以 print 函数只有在 $i == 2 为真时才被调用(print 的值被当成了上述的可选数字参数而传递给了 continue)。
continue 的更新记录
版本 | 说明 |
---|---|
5.4.0 | continue 0; 不再合法。这在之前的版本被解析为 continue 1;。 |
5.4.0 | 取消变量作为参数传递(例如 $num = 2; continue $num;)。 |
(十二)switch
(PHP 4, PHP 5)
switch 语句类似于具有同一个表达式的一系列 if 语句。很多场合下需要把同一个变量(或表达式)与很多不同的值比较,并根据它等于哪个值来执行不同的代码。这正是 switch 语句的用途。
Note: 注意和其它语言不同,continue 语句作用到 switch 上的作用类似于 break。如果在循环中有一个 switch 并希望 continue 到外层循环中的下一轮循环,用 continue 2。
- Note:注意 switch/case 作的是松散比较。
下面两个例子使用两种不同方法实现同样的事,一个用一系列的 if 和 elseif 语句,另一个用 switch 语句:
Example #1 switch 结构
<?php
if ( $i == 0 ) {
echo "i equals 0" ;
} elseif ( $i == 1 ) {
echo "i equals 1" ;
} elseif ( $i == 2 ) {
echo "i equals 2" ;
}
switch ( $i ) {
case 0 :
echo "i equals 0" ;
break;
case 1 :
echo "i equals 1" ;
break;
case 2 :
echo "i equals 2" ;
break;
}
?>
Example #2 switch 结构可以用字符串
<?php
switch ( $i ) {
case "apple" :
echo "i is apple" ;
break;
case "bar" :
echo "i is bar" ;
break;
case "cake" :
echo "i is cake" ;
break;
}
?>
为避免错误,理解 switch 是怎样执行的非常重要。switch 语句一行接一行地执行(实际上是语句接语句)。开始时没有代码被执行。仅当一个 case 语句中的值和 switch 表达式的值匹配时 PHP 才开始执行语句,直到 switch 的程序段结束或者遇到第一个 break 语句为止。如果不在 case 的语句段最后写上 break 的话,PHP 将继续执行下一个 case 中的语句段。例如:
<?php
switch ( $i ) {
case 0 :
echo "i equals 0" ;
case 1 :
echo "i equals 1" ;
case 2 :
echo "i equals 2" ;
}
?>
这里如果 $i 等于 0,PHP 将执行所有的 echo 语句!如果 $i 等于 1,PHP 将执行后面两条 echo 语句。只有当 $i 等于 2 时,才会得到“预期”的结果——只显示“i equals 2”。所以,别忘了 break 语句就很重要(即使在某些情况下故意想避免提供它们时)。
在 switch 语句中条件只求值一次并用来和每个 case 语句比较。在 elseif 语句中条件会再次求值。如果条件比一个简单的比较要复杂得多或者在一个很多次的循环中,那么用 switch 语句可能会快一些。
在一个 case 中的语句也可以为空,这样只不过将控制转移到了下一个 case 中的语句。
<?php
switch ( $i ) {
case 0 :
case 1 :
case 2 :
echo "i is less than 3 but not negative" ;
break;
case 3 :
echo "i is 3" ;
}
?>
一个 case 的特例是 default。它匹配了任何和其它 case 都不匹配的情况。例如:
<?php
switch ( $i ) {
case 0 :
echo "i equals 0" ;
break;
case 1 :
echo "i equals 1" ;
break;
case 2 :
echo "i equals 2" ;
break;
default:
echo "i is not equal to 0, 1 or 2" ;
}
?>
case 表达式可以是任何求值为简单类型的表达式,即整型或浮点数以及字符串。不能用数组或对象,除非它们被解除引用成为简单类型。
switch 支持替代语法的流程控制。更多信息见流程控制的替代语法一节。
<?php
switch ( $i ):
case 0 :
echo "i equals 0" ;
break;
case 1 :
echo "i equals 1" ;
break;
case 2 :
echo "i equals 2" ;
break;
default:
echo "i is not equal to 0, 1 or 2" ;
endswitch;
?>
允许使用分号代替 case 语句后的冒号,例如:
<?php
switch( $beer )
{
case 'tuborg' ;
case 'carlsberg' ;
case 'heineken' ;
echo 'Good choice' ;
break;
default;
echo 'Please make a new selection...' ;
break;
}
?>
(十三)declare
(PHP 4, PHP 5)
declare 结构用来设定一段代码的执行指令。declare 的语法和其它流程控制结构相似:
declare (directive)
statement
directive 部分允许设定 declare 代码段的行为。目前只认识两个指令:ticks(更多信息见下面 ticks 指令)以及 encoding(更多信息见下面 encoding 指令)。
- Note: encoding 是 PHP 5.3.0 新增指令。
declare 代码段中的 statement 部分将被执行——怎样执行以及执行中有什么副作用出现取决于 directive 中设定的指令。
declare 结构也可用于全局范围,影响到其后的所有代码(但如果有 declare 结构的文件被其它文件包含,则对包含它的父文件不起作用)。
<?php
// these are the same:
// you can use this:
declare( ticks = 1 ) {
// entire script here
}
// or you can use this:
declare( ticks = 1 );
// entire script here
?>
Ticks
Tick(时钟周期)是一个在 declare 代码段中解释器每执行 N 条可计时的低级语句就会发生的事件。 N 的值是在 declare 中的 directive 部分用 ticks= N 来指定的。
不是所有语句都可计时。通常条件表达式和参数表达式都不可计时。
在每个 tick 中出现的事件是由 register_tick_function() 来指定的。更多细节见下面的例子。注意每个 tick 中可以出现多个事件。
Example #1 Tick 的用法示例
<?php
declare( ticks = 1 );
// A function called on each tick event
function tick_handler ()
{
echo "tick_handler() called\n" ;
}
register_tick_function ( 'tick_handler' );
$a = 1 ;
if ( $a > 0 ) {
$a += 2 ;
print( $a );
}
?>
Example #2 Ticks 的用法示例
<?php
function tick_handler ()
{
echo "tick_handler() called\n" ;
}
$a = 1 ;
tick_handler ();
if ( $a > 0 ) {
$a += 2 ;
tick_handler ();
print( $a );
tick_handler ();
}
tick_handler ();
?>
参见 register_tick_function() 和 unregister_tick_function() 。
Encoding
可以用 encoding 指令来对每段脚本指定其编码方式。
Example #3 对脚本指定编码方式
<?php
declare( encoding = 'ISO-8859-1' );
// code here
?>
Caution
当和命名空间结合起来时 declare 的唯一合法语法是 declare(encoding='...');,其中 ... 是编码的值。而 declare(encoding='...') {} 将在与命名空间结合时产生解析错误。
在 PHP 5.3 中除非在编译时指定了 --enable-zend-multibyte,否则 declare 中的 encoding 值会被忽略。
注意除非用 phpinfo() ,否则 PHP 不会显示出是否在编译时指定了 --enable-zend-multibyte。
参见 zend.script_encoding。
(十四)return
(PHP 4, PHP 5)
如果在一个函数中调用 return 语句,将立即结束此函数的执行并将它的参数作为函数的值返回。 return 也会终止 eval() 语句或者脚本文件的执行。
如果在全局范围中调用,则当前脚本文件中止运行。如果当前脚本文件是被 include 的或者 require 的,则控制交回调用文件。此外,如果当前脚本是被 include 的,则 return 的值会被当作 include 调用的返回值。如果在主脚本文件中调用 return ,则脚本中止运行。如果当前脚本文件是在 php.ini 中的配置选项 auto_prepend_file 或者 auto_append_file 所指定的,则此脚本文件中止运行。
更多信息见返回值。
- Note: 注意既然 return 是语言结构而不是函数,因此其参数没有必要用括号将其括起来。通常都不用括号,实际上也应该不用,这样可以降低 PHP 的负担。
- Note: 如果没有提供参数,则一定不能用括号,此时返回 NULL 。如果调用 return 时加上了括号却又没有参数会导致解析错误。
- Note: 当用引用返回值时永远不要使用括号,这样行不通。只能通过引用返回变量,而不是语句的结果。如果使用 return ($a); 时其实不是返回一个变量,而是表达式 ($a) 的值(当然,此时该值也正是 $a 的值)。
(十五)require
(PHP 4, PHP 5)
require 和 include 几乎完全一样,除了处理失败的方式不同之外。 require 在出错时产生 E_COMPILE_ERROR 级别的错误。换句话说将导致脚本中止而 include 只产生警告( E_WARNING ),脚本会继续运行。
参见 include 文档了解详情。
(十六)include
(PHP 4, PHP 5)
include 语句包含并运行指定文件。
以下文档也适用于 require 。
被包含文件先按参数给出的路径寻找,如果没有给出目录(只有文件名)时则按照 include_path 指定的目录寻找。如果在 include_path 下没找到该文件则 include 最后才在调用脚本文件所在的目录和当前工作目录下寻找。如果最后仍未找到文件则 include 结构会发出一条警告;这一点和 require 不同,后者会发出一个致命错误。
如果定义了路径——不管是绝对路径(在 Windows 下以盘符或者 \ 开头,在 Unix/Linux 下以 / 开头)还是当前目录的相对路径(以 . 或者 .. 开头)——include_path 都会被完全忽略。例如一个文件以 ../ 开头,则解析器会在当前目录的父目录下寻找该文件。
有关 PHP 怎样处理包含文件和包含路径的更多信息参见 include_path 部分的文档。
当一个文件被包含时,其中所包含的代码继承了 include 所在行的变量范围。从该处开始,调用文件在该行处可用的任何变量在被调用的文件中也都可用。不过所有在包含文件中定义的函数和类都具有全局作用域。
Example #1
基本的 include 例子 vars.php
<?php
$color = 'green' ;
$fruit = 'apple' ;
?>
test.php
<?php
echo "A $color $fruit " ; // A
include 'vars.php' ;
echo "A $color $fruit " ; // A green apple
?>
如果 include 出现于调用文件中的一个函数里,则被调用的文件中所包含的所有代码将表现得如同它们是在该函数内部定义的一样。所以它将遵循该函数的变量范围。此规则的一个例外是魔术常量,它们是在发生包含之前就已被解析器处理的。
Example #2
函数中的包含
<?php
function foo ()
{
global $color ;
include 'vars.php' ;
echo "A $color $fruit " ;
}
/* vars.php is in the scope of foo() so *
* $fruit is NOT available outside of this *
* scope. $color is because we declared it *
* as global. */
foo (); // A green apple
echo "A $color $fruit " ; // A green
?>
当一个文件被包含时,语法解析器在目标文件的开头脱离 PHP 模式并进入 HTML 模式,到文件结尾处恢复。由于此原因,目标文件中需要作为 PHP 代码执行的任何代码都必须被包括在有效的 PHP 起始和结束标记之中。
如果“URL fopen wrappers”在 PHP 中被激活(默认配置),可以用 URL(通过 HTTP 或者其它支持的封装协议——见支持的协议和封装协议)而不是本地文件来指定要被包含的文件。如果目标服务器将目标文件作为 PHP 代码解释,则可以用适用于 HTTP GET 的 URL 请求字符串来向被包括的文件传递变量。严格的说这和包含一个文件并继承父文件的变量空间并不是一回事;该脚本文件实际上已经在远程服务器上运行了,而本地脚本则包括了其结果。
Warning: Windows 版本的 PHP 在 4.3.0 版之前不支持通过此函数访问远程文件,即使已经启用 allow_url_fopen.
Example #3
通过 HTTP 进行的 include
<?php
/* This example assumes that www.example.com is configured to parse .php *
* files and not .txt files. Also, 'Works' here means that the variables *
* $foo and $bar are available within the included file. */
// Won't work; file.txt wasn't handled by www.example.com as PHP
include 'http://www.example.com/file.txt?foo=1&bar=2' ;
// Won't work; looks for a file named 'file.php?foo=1&bar=2' on the
// local filesystem.
include 'file.php?foo=1&bar=2' ;
// Works.
include 'http://www.example.com/file.php?foo=1&bar=2' ;
$foo = 1 ;
$bar = 2 ;
include 'file.txt' ; // Works.
include 'file.php' ; // Works.
?>
Warning:安全警告,远程文件可能会经远程服务器处理(根据文件后缀以及远程服务器是否在运行 PHP 而定),但必须产生出一个合法的 PHP 脚本,因为其将被本地服务器处理。如果来自远程服务器的文件应该在远端运行而只输出结果,那用 readfile() 函数更好。另外还要格外小心以确保远程的脚本产生出合法并且是所需的代码。
相关信息参见使用远程文件, fopen() 和 file() 。
处理返回值:在失败时 include 返回 FALSE 并且发出警告。成功的包含则返回 1,除非在包含文件中另外给出了返回值。可以在被包括的文件中使用 return 语句来终止该文件中程序的执行并返回调用它的脚本。同样也可以从被包含的文件中返回值。可以像普通函数一样获得 include 调用的返回值。不过这在包含远程文件时却不行,除非远程文件的输出具有合法的 PHP 开始和结束标记(如同任何本地文件一样)。可以在标记内定义所需的变量,该变量在文件被包含的位置之后就可用了。
因为 include 是一个特殊的语言结构,其参数不需要括号。在比较其返回值时要注意。
Example #4
比较 include 的返回值
<?php
// won't work, evaluated as include(('vars.php') == 'OK'), i.e. include('')
if (include( 'vars.php' ) == 'OK' ) {
echo 'OK' ;
}
// works
if ((include 'vars.php' ) == 'OK' ) {
echo 'OK' ;
}
?>
Example #5
include 和 return 语句
return.php
<?php
$var = 'PHP' ;
return $var ;
?>
noreturn.php
<?php
$var = 'PHP' ;
?>
testreturns.php
<?php
$foo = include 'return.php' ;
echo $foo ; // prints 'PHP'
$bar = include 'noreturn.php' ;
echo $bar ; // prints 1
?>
$bar 的值为 1 是因为 include 成功运行了。注意以上例子中的区别。第一个在被包含的文件中用了 return 而另一个没有。如果文件不能被包含,则返回 FALSE 并发出一个 E_WARNING 警告。
如果在包含文件中定义有函数,这些函数不管是在 return 之前还是之后定义的,都可以独立在主文件中使用。如果文件被包含两次,PHP 5 发出致命错误因为函数已经被定义,但是 PHP 4 不会对在 return 之后定义的函数报错。推荐使用 include_once 而不是检查文件是否已包含并在包含文件中有条件返回。
另一个将 PHP 文件“包含”到一个变量中的方法是用输出控制函数结合 include 来捕获其输出,例如:
Example #6
使用输出缓冲来将 PHP 文件包含入一个字符串
<?php
$string = get_include_contents ( 'somefile.php' );
function get_include_contents ( $filename ) {
if ( is_file ( $filename )) {
ob_start ();
include $filename ;
$contents = ob_get_contents ();
ob_end_clean ();
return $contents ;
}
return false ;
}
?>
要在脚本中自动包含文件,参见 php.ini 中的 auto_prepend_file 和 auto_append_file 配置选项。
Note: 因为是一个语言构造器而不是一个函数,不能被 可变函数 调用。
参见 require , require_once , include_once , get_included_files() , readfile() , virtual() 和 include_path。
(十七)require_once
(PHP 4, PHP 5)
require_once 语句和 require 语句完全相同,唯一区别是 PHP 会检查该文件是否已经被包含过,如果是则不会再次包含。
参见 include_once 的文档来理解 _once 的含义,并理解与没有 _once 时候有什么不同。
(十八)include_once
(PHP 4, PHP 5)
include_once 语句在脚本执行期间包含并运行指定文件。此行为和 include 语句类似,唯一区别是如果该文件中已经被包含过,则不会再次包含。如同此语句名字暗示的那样,只会包含一次。
include_once 可以用于在脚本执行期间同一个文件有可能被包含超过一次的情况下,想确保它只被包含一次以避免函数重定义,变量重新赋值等问题。
更多信息参见 include 文档。
Note:在 PHP 4中,_once 的行为在不区分大小写字母的操作系统(例如 Windows)中有所不同,例如:
Example #1
include_once 在 PHP 4 运行于不区分大小写的操作系统中
<?php
include_once "a.php" ; // 这将包含 a.php
include_once "A.php" ; // 这将再次包含 a.php!(仅 PHP 4)
?>
此行为在 PHP 5 中改了,例如在 Windows 中路径先被规格化,因此 C:\PROGRA~1\A.php 和 C:\Program Files\a.php 的实现一样,文件只会被包含一次。
(十九)goto
(PHP 5 >= 5.3.0)
goto 操作符可以用来跳转到程序中的另一位置。该目标位置可以用目标名称加上冒号来标记,而跳转指令是 goto 之后接上目标位置的标记。PHP 中的 goto 有一定限制,目标位置只能位于同一个文件和作用域,也就是说无法跳出一个函数或类方法,也无法跳入到另一个函数。也无法跳入到任何循环或者 switch 结构中。可以跳出循环或者 switch,通常的用法是用 goto 代替多层的 break。
Example #1
goto 示例
<?php
goto a ;
echo 'Foo' ;
a :
echo 'Bar' ;
?>
以上例程会输出:
Bar
Example #2
goto 跳出循环示例
<?php
for( $i = 0 , $j = 50 ; $i < 100 ; $i ++) {
while( $j --) {
if( $j == 17 ) goto end ;
}
}
echo "i = $i " ;
end :
echo 'j hit 17' ;
?>
以上例程会输出:
j hit 17
Example #3
以下写法无效
<?php
goto loop ;
for( $i = 0 , $j = 50 ; $i < 100 ; $i ++) {
while( $j --) {
loop :
}
}
echo " $i = $i " ;
?>
以上例程会输出:
Fatal error: 'goto' into loop or switch statement is disallowed in
script on line 2
Note: goto 操作符仅在 PHP 5.3及以上版本有效。
八、函数
(一)用户自定义函数
(二)函数的参数
(三)返回值
(四)可变函数
(五)内部(内置)函数
(六)匿名函数
九、类与对象
(一)简介
(二)基本概念
(三)属性
(四)类常量
(五)自动加载类
(六)构造函数和析构函数
(七)访问控制(可见性)
(八)对象继承
(九)范围解析操作符(::)
(十)Static(静态)关键字
(十一)抽象类
(十二)对象接口
(十三)Traits
(十四)Anonymous classes
(十五)重载
(十六)遍历对象
(十七)魔术方法
(十八)Final 关键字
(十九)对象复制
(二十)对象比较
(二十一)类型约束
(二十二)后期静态绑定
(二十三)对象和引用
(二十四)对象序列化
(二十五)OOP 变更日志
十、命名空间
(一)命名空间概述
(二)定义命名空间
(三)定义子命名空间
(四)在同一个文件中定义多个命名空间
(五)使用命名空间:基础
(六)命名空间和动态语言特征
(七)namespace关键字和`__NAMESPACE__`常量
(八)使用命名空间:别名/导入
(九)全局空间
(十)使用命名空间:后备全局函数/常量
(十一)名称解析规则
(十二)FAQ: things you need to know about namespaces
十一、Errors
(一)Basics
(二)Errors in PHP 7
十二、异常处理
(一)扩展(extend) PHP 内置的异常处理类
十三、生成器
(一)生成器总览
(二)生成器语法
(三)Comparing generators with Iterator objects
十四、引用的解释
(一)引用是什么
(二)引用做什么
(三)引用不是什么
(四)引用传递
(五)引用返回
(六)取消引用
(七)引用定位
十五、预定义变量
(一)超全局变量 — 超全局变量是在全部作用域中始终可用的内置变量
(二)$GLOBALS — 引用全局作用域中可用的全部变量
(三)$_SERVER — 服务器和执行环境信息
(四)$_GET — HTTP GET 变量
(五)$_POST — HTTP POST 变量
(六)$_FILES — HTTP 文件上传变量
(七)$_REQUEST — HTTP Request 变量
(八)$_SESSION — Session 变量
(九)$_ENV — 环境变量
(十)$_COOKIE — HTTP Cookies
(十一)$php_errormsg — 前一个错误信息
(十二)$HTTP_RAW_POST_DATA — 原生POST数据
(十三)$http_response_header — HTTP 响应头
(十四)$argc — 传递给脚本的参数数目
(十五)$argv — 传递给脚本的参数数组
十六、预定义异常
(一)Exception
(二)ErrorException
十七、预定义接口
(一)遍历 — Traversable(遍历)接口
(二)迭代器 — Iterator(迭代器)接口
(三)聚合式迭代器 — IteratorAggregate(聚合式迭代器)接口
(四)数组式访问 — ArrayAccess(数组式访问)接口
(五)序列化 — 序列化接口
(六)Closure — Closure 类
(七)生成器 — 生成器类
十八、上下文(Context)选项和参数
(一)套接字上下文选项 — 套接字上下文选项列表
(二)HTTP context 选项 — HTTP context 的选项列表
(三)FTP context options — FTP context option listing
(四)SSL 上下文选项 — SSL 上下文选项清单
(五)CURL context options — CURL 上下文选项列表
(六)Phar 上下文(context)选项 — Phar 上下文(context)选项列表
(七)MongoDB context options — MongoDB context option listing
(八)Context 参数 — Context 参数列表
十九、支持的协议和封装协议
(一)file:// — 访问本地文件系统
(二)http:// — 访问 HTTP(s) 网址
(三)ftp:// — 访问 FTP(s) URLs
(四)php:// — 访问各个输入/输出流(I/O streams)
(五)zlib:// — 压缩流
(六)data:// — 数据(RFC 2397)
(七)glob:// — 查找匹配的文件路径模式
(八)phar:// — PHP 归档
(九)ssh2:// — Secure Shell 2
(十)rar:// — RAR
(十一)ogg:// — 音频流
(十二)expect:// — 处理交互式的流
本作品采用 知识共享署名-相同方式共享 4.0 国际许可协议 进行许可。