PHP表达式是PHP程序最为重要的组成部分,PHP表达式指的是将相同数据类型或不同数据类型的数据(如变量、常量、函数等),用运算符号按一定的规则连接起来的、有意义的式子。本章围绕表达式详细讲解表达式中涉及的变量、常量以及常用运算符,最后讨论表达式中数据类型之间的相互转换。
3.1 常 量
PHP有时使用常量实现数据在内存中的存储,使用常量名实现内存数据的按名存取。常量是指在程序运行过程中始终保持不变的量。常量一旦被定义,常量的值以及常量的数据类型将不再发生变化。PHP常量分为自定义常量和预定义常量。
3.1.1 自定义常量
自定义常量在使用前必须定义,PHP的define()函数专门用于定义自定义常量,define()函数的语法格式为:define(name,value[, boolean case_insensitive])。
函数功能:定义一个名字为name,值为value的常量。case_insensitive参数的默认值为FALSE,表示常量名name大小写敏感(区分大小写);case_insensitive参数值如果为TRUE,表示常量名name大小写不敏感(不区分大小写)。
函数说明:常量名name为字符串类型数据,常量值value必须是标量数据类型数据。
例如,程序define.php如下。
常量的定义及使用注意如下几点。
(1)常量必须使用define()函数定义,常量名前面不加前缀“$”符号。
(2)常量名由字母或者下画线开头,后面跟上任意数量的字母、数字或者下画线。
(3)常量名可以是全部大写、全部小写或者大小写混合,但一般习惯是全部大写。
(4)常量的作用域是全局的,不存在使用范围的问题,可以在程序任意位置进行定义和使用常量。
(5)常量一旦被定义,其值不能在程序运行过程中修改,也不能被销毁。例如,程序defineError.php如下,该程序的运行结果如图3-1所示。
<?php
define("DATABASE","student");
//重新定义DATABASE常量,此时将出现Notice信息
define("DATABASE","root",FALSE);
echo DATABASE;//输出:student
?>
由于程序defineError.php试图修改已定义常量DATABASE的值,程序产生Notice信息。从程序的运行结果可以看出,PHP产生Notice信息后,并不会影响程序的继续运行。
3.1.2 常量的内存分配
内存中专门为常量的存储分配了一个空间:常量存储区。常量存储区是一块比较特殊的存储空间,位于该存储空间的常量是全局的,且在程序运行期间不能修改和销毁。程序define.php运行过程中的内存分配图如图3-2所示。
3.1.3 预定义常量
PHP预定义了许多常量,这些常量无需使用define()函数定义,可直接在程序中使用。下面列举了一些常用的PHP预定义常量。
(1)FILE(FILE前后是两个下画线):当前正在处理的脚本文件名,若使用在一个被引用的文件中(include或require),那么它的值就是被引用的文件,而不是引用它的那个文件。
(2)LINE(LINE前后是两个下画线):正在处理的脚本文件的当前行数。
(3)PHP_VERSION:当前 PHP预处理器的版本,如5.3.0。
(4)PHP_OS:PHP所在的操作系统的类型,如Linux。
(5)TRUE:表示逻辑真。FALSE:表示逻辑假。NULL:表示没有值或值不确定。
(6)DIRECTORY_SEPARATOR:表示目录分隔符,UNIX或Linux操作系统环境时的值为“/”,Windows操作系统环境时的值为“\”。例如,程序preDefined.php如下。
3.2 变 量
PHP更多时候使用变量实现数据在内存中的存储,变量是PHP表达式中最重要的组成部分。PHP变量可分为自定义变量和预定义变量,本章所谈到的变量为自定义变量。
3.2.1 变量基本概念
变量是用于临时存储数据的容器,这些数据可以是任意一种数据类型的数据。变量通过变量名实现内存数据的按名存取。PHP中的变量名遵循以下规则。
(1)变量名必须以美元符号($)开头,如$userName
(2)变量名的第1个字符必须是字母或下画线(不能是数字),变量名称可以为字母、数字和下画线的组合,如$user_name_1。
(3)PHP中的变量名是区分大小写的,这是一个非常重要的规则。这意味着$userName和$UserName是截然不同的两个变量。
和传统的高级语言不一样,PHP中对于已经定义的变量可以通过重新赋值的方法修改该变量的值,甚至修改该变量的数据类型。例如,程序variable.php如下。
3.2.2 变量的内存分配
内存除了存在一个常量存储区专门用于存储常量外,还有一段栈空间用于存储变量。栈是一种数据结构,它是一种只能在某一端插入和删除的特殊线性表。栈按照后进先出的原则存储数据,先进入的数据被压入栈底,最后的数据在栈顶,栈底固定,而栈顶浮动。插入一个元素的过程称为入栈(PUSH),删除一个元素的过程则称为出栈(POP)。栈的逻辑结构如图3-3所示。程序variable.php运行过程中的内存分配图如图3-4所示。
(1)程序准备执行时,内存处于初始状态,此时栈内存和内存中没有任何数据。
(2)程序执行到“$userName = "张三";”语句时,称为过程1。过程1后,栈内存和内存中将添加变量$userName及对应的值"张三"。
(3)程序执行到“$userName = "李四";”语句时,称为过程2。过程2后,内存中将添加变量$userName对应的值"李四"。
(4)此后由于内存中"张三"数据没有被其他变量名所引用(指向),"张三"将视为垃圾数据被PHP垃圾回收机制在“适当”时刻回收,以便节省内存开支,该过程称为过程3。
(5)程序执行到“$sex = FALSE;”语句时,称为过程4。过程4后,栈内存和内存中将添加变量$sex及对应的值FALSE。
(6)程序执行到“$sex = "男";”语句时,称为过程5。过程5后,内存中将添加变量$sex对应的值"男"。
(7)此后由于FALSE在内存中没有被其他变量名所引用(指向),FALSE将被视为垃圾数据被PHP垃圾回收机制在“适当”时刻回收,以便节省内存开支。该过程称为过程6。
(8)当程序variable.php中的所有代码执行完毕后,PHP垃圾回收机制首先回收位于栈顶的变量$sex,该过程为过程7。
(9)最后PHP垃圾回收机制回收位于栈底的变量$userName,该过程为过程8。过程8后,内存又处于初始状态,为运行其他PHP程序做准备。
3.2.3 变量赋值方式
变量赋值是指赋予变量具体的数据,使用赋值运算符“=”来实现。PHP提供两种赋值方式:传值赋值和传地址赋值。
1.传值赋值方式
前面所有的程序都是使用传值赋值方式为变量赋值,传值赋值方式将一个值的“拷贝”赋值给某个变量。例如,程序byValue.php如下,该程序运行过程中的内存分配图如图3-5所示。
对图3-5的部分说明如下。
(1)当程序执行到“$age2 = $age1;”语句时,称为过程2。过程2后,内存中并没有新增变量$age2的变量值18,这是由于PHP为了提高内存的使用效率,采用了“写时拷贝”的原理对变量进行赋值。简言之,除非发生写(或修改)操作,否则指向同一个地址的变量值或者对象将不会被拷贝,这样既节省内存又提高了代码的执行效率。
(2)当程序执行到“$age2 = 20;”语句时,称为过程3。过程3后,内存才添加了变量$age2的变量值20。
2.传地址赋值方式
传地址赋值是将源变量的内存地址赋值给新的变量,即新的变量引用了源变量的值,改动新变量的值将影响到源变量的值,反之亦然。传地址赋值意味着两个变量都指向同一个数据,不存在任何数据的拷贝过程。PHP通过在源变量($oldVariable)前追加“&”符号实现传地址赋值,语法格式为:$newVariable = &$oldVariable。例如程序byReference.php如下,该程序运行过程中的内存分配图如图3-6所示。
对图3-6的部分说明如下。
(1)当程序执行到“$age2 = &$age1”;语句时,称为过程2。经过过程2后,变量$age2与变量$age1指向了内存中同一个变量值18。
(2)当程序执行到“$age2 = 20”;语句时,称为过程3。过程3后,变量$age2与变量$age1指向了内存中同一个变量值20。
3.2.4 可变变量
PHP提供了一种特殊类型的变量:可变变量。可变变量允许PHP程序动态地改变一个变量的变量名,可变变量的工作原理是用一个变量的“值”作为另一个变量的“名”。例如,程序variableNameChanged.php如下。
3.3 有关变量或常量状态的函数
PHP数据在内存中要么以变量的方式存储,要么以常量的方式存储,PHP提供了用于判断和修改变量或常量状态的函数。
3.3.1 数据类型查看函数
PHP为变量或常量提供了查看数据类型的函数,其中包括gettype()和var_dump()函数。
1.gettype()函数
语法格式:string gettype ( mixed var )
函数功能:gettype()函数需要变量名(带$符号)或常量名作为参数,该函数返回变量或常量的数据类型,这些数据类型包括:integer、double、string、array、object、unknown type(未知数据类型)等。
2.var_dump()函数
语法格式:void var_dump (mixed var )
函数功能:var_dump()函数需要传递一个变量名(带$符号)或常量名作为参数,该函数可以得到变量或常量的数据类型以及对应的值,并将这些信息输出。
函数说明:void表示函数var_dump()函数没有返回值。调试程序时,经常使用var_dump()函数查看变量或常量的值、数据类型等信息。例如,程序dataType.php如下。
3.3.2 检查常量或变量是否定义函数
1.defined()函数
语法格式:bool defined (string name)
函数功能:检查常量是否经过define()函数定义。该函数参数为常量名(注意常量名必须带双引号或单引号),如果常量经过define()函数定义,该函数返回布尔值TRUE,否则返回FALSE。例如,程序defined.php如下,该程序的运行结果如图3-7所示。从运行结果可以看出,常量(如STUDENT)若没有经define()函数定义,常量的值为常量名字符串。
2.isset()函数
语法格式:bool isset (mixed var)
函数功能:检查变量var是否定义。该函数参数为变量名(带$号),如果变量已经定义,该函数返回布尔值TRUE,否则返回FALSE。例如,程序isset.php如下,该程序的运行结果如图3-8所示。
<?php
$age = 20;
if(isset($age)){
echo '变量$age已经定义';
}
?>
3.3.3 取消变量定义unset()函数
unset()函数语法格式:void unset ( mixed var )
函数功能:取消变量var的定义。该函数的参数为变量名(带$符号),函数没有返回值。例如程序unset.php如下,该程序的运行结果如图3-9所示,程序运行过程中的内存分配图如图3-10所示。
对图3-10的部分说明:当程序执行到语句“unset($age1);”时,称为过程4。使用unset()函数,只是断开了变量名和变量的值之间的联系,没有立即销毁变量,变量由PHP垃圾回收机制在“适当”时刻进行回收。
3.3.4 检查变量是否为“空”
PHP提供了检查变量是否为“空”的两个函数:empty()函数和is_null()函数。
1.empty()函数
语法格式:boolean empty ( mixed var )
函数功能:用于检查变量var是否为“空”,该函数参数var为变量名(带$号)。如果变量var为空,则empty()函数返回TRUE,否则返回FALSE。例如,程序empty.php如下。
2.is_null()函数
语法格式:boolean is_ null( mixed var )
函数功能:检查变量var是否为NULL,如果值为NULL则返回TRUE,否则返回FALSE。
函数说明:is_null()函数用于判断变量是否为NULL时,可以看做isset()函数的反函数。下面的3种情况变量的值为NULL。
(1)变量未经定义。
(2)变量的值赋值为NULL。
(3)变量经unset()函数处理后。
例如,程序is_null.php如下,该程序的运行结果如图3-11所示。
3.3.5 数据类型检查函数
PHP为变量或常量提供了检查数据类型的函数(见表3-1),这些函数的共同特征是:需要向这些函数传递一个变量名(带$符号)或常量名(注意常量名必须带双引号或单引号)作为参数,如果检查符合要求,函数返回TRUE,否则返回FALSE。例如,程序typeChecked.php如下。
3.4 PHP运算符
运算符是数据操作的符号,是表达式另外一个重要组成部分。根据运算符功能的不同,可将PHP的运算符分为算术、赋值、位、比较、错误控制、执行、递增/递减、逻辑、字符串连接、条件等运算符。不同的运算符所需操作数的个数也不相同,根据运算符操作数个数的不同,可将运算符分为单目运算符、双目运算符和三目运算符。
3.4.1 算术运算符
PHP算术运算符可以实现算术运算,PHP中的算术运算符如表3-2所示。例如,程序calculator.php如下。
3.4.2 递增/递减运算符
PHP中的递增/递减运算符如表3-3所示。例如,程序increase.php如下。
3.4.3 赋值运算符
赋值运算符“=”是将“=”右边表达式的值赋给左边的变量。赋值运算符产生的表达式为赋值表达式,该表达式的值为“=”左边的变量值。例如,程序assign.php如下。
除此之外,PHP还提供适合于所有二元算术养生法和字符串运算符的“组和运算符”:+=、-=、 *=、 /=、 %=、 .=等。这样可以在一个表达式中使用一个值(如$y)并把表达式的结果赋给另一个值(如$x)(见表3-4)。例如,程序combination.php如下。
3.4.4 比较运算符
比较运算符用来对两个表达式的值进行比较,比较的结果是一个布尔值(要么是TRUE,要么是FALSE)。如果表达式是数值,则按照数值大小进行比较;如果表达式是字符串,则按照每个字符所对应的ASCII值比较。表3-5所示为PHP中的比较运算符。例如,程序compare.php如下。
3.4.5 逻辑运算符
逻辑运算符对布尔型数据进行操作,并返回布尔型结果。表3-6所示为PHP中的逻辑运算符。例如,程序logic1.php如下。
例如,程序logic2.php如下。
3.4.6 字符串连接运算符
字符串连接运算符只有一个点运算符“.”,使用“.”运算符可以将两个字符串连接成一个字符串。例如,程序string.php如下。
<?php
echo "hello world!"."< br/>".date("Y年m月d日h时i分s秒");
?>
3.4.7 错误抑制运算符
当PHP表达式产生错误而又不想将错误信息显示在页面上时,可以使用错误抑制运算符“@”。将“@”运算符放置在PHP表达式之前,该表达式产生的任何错误信息将不会输出。这样做有以下两个好处。
(1)安全:避免错误信息外露,造成系统漏洞。
(2)美观:避免浏览器页面出现错误信息,影响页面美观。
例如,程序errorControl.php如下,该程序的运行结果如图3-12所示。
注意:在程序errorControl.php中,“@print $age”;语句中不能将print替换成echo,否则将出现程序解析错误:“Parse error: parse error in C:\wamp\www\2\sample.php on line 7”。
在出现数据库连接、打开文件流、除0等异常时,可以用@符号来抑制函数或表达式错误信息。例如,程序errorControl2.php如下。
<?php
@mysql_connect("localhost","root","");
@fopen("unknown.gif","r");
@$a = (5/0);
?>
3.4.8 条件运算符
条件运算符的语法格式为:表达式1?表达式2:表达式3
由条件运算符组成的表达式称为条件表达式,条件表达式的执行过程为:如果表达式1 的值为TRUE,则整个条件表达式的值为表达式2的值;如果表达式1的值为FALSE,则整个条件表达式的值为表达式3的值。条件运算符中有3个操作数,因此条件运算符为三目运算符。例如,程序condition.php如下。
<?php
$a = 0.0;
$b = ($a==0)?"zero":"not zero";
echo $b;//输出:zero
?>
3.4.9 类型运算符
PHP 5提供了类型运算符instanceof,该运算符用于判断一个对象是否是某个类的对象。例如,程序instanceof.php如下。
<?php
class A{
}
class B{
}
$a = new A();
var_dump($a instanceof A); //输出:bool(true)
echo "
";
var_dump($a instanceof B); //输出:bool(false)
?>
3.4.10 执行运算符
执行运算符使用反引号(`)(注意这不是单引号!一般是键盘上ESC下面的按键)。执行运算符尝试将反引号中的字符串内容作为操作系统系统命令来执行(如Linux的shell命令或Windows的DOS命令),并返回该系统命令的执行结果。例如,程序exec.php如下。
3.4.11 位运算符
位运算符主要用于整型数据的运算,当表达式包含位运算符时,运算时会先将各整型数据转换为相应的二进制数,然后再进行位运算。PHP提供的位运算符如表3-7所示。例如,程序bit.php如下。
3.4.12 运算符优先级
一个复杂的表达式往往包含了多种运算符,表达式运算时,运算符优先级的不同,各运算符执行的顺序也不相同,高优先级的运算符会先被执行,低优先级的运算符会后被执行。PHP中各运算符的优先级由高到低的顺序如表3-8所示。在实际编程过程中,使用括号“()”是避免优先级混乱的最有效方法。
3.5 数据类型的转换
PHP中任何变量或常量都有一个“隐式的”数据类型,数据类型是由赋给变量或常量的值自动确定的。同一表达式中可以包含不同数据类型的常量及变量,这些常量或变量进行计算前,须转换为同一数据类型的数据。PHP类型转换包括类型自动转换和强制转换。
3.5.1 类型自动转换
类型自动转换是指在定义变量或常量时,不需要指定变量或常量的数据类型,由PHP预处理器根据具体应用环境,将变量或常量转换为合适的数据类型。例如,当字符串执行算术运算时,PHP预处理器会将字符串转换为数值类型后,再进行算术运算;当数值执行字符串连接运算,PHP预处理器会将数值转换为字符串类型后,再进行字符串连接运算。类型自动转换基本规则如下。
(1)布尔型数据参与算术运算时,TRUE被转换为整数1,FALSE被转换为整数0;NULL参与算术运算时,被转换为整数0。例如,程序rules1.php如下。
(2)浮点数与整数进行算术运算时,将整数转换为浮点数后,再进行算术运算。例如,程序rules2.php如下。
说明:程序rules2.php执行算术运算时,先将TRUE转换为整数1,再将整数1转换为浮点数1进行运算。
(3)参与算术运算的字符串,只有以数字开头的字符串才会被认作数字。字符串开头部分符合整数格式时,字符串将被转换为整数,例如在执行算术运算时字符串"3rd degree"将被转换为整数3;字符串开头部分符合浮点数格式时(字符串开头中可以包含“.”、“e”或“E”字符),字符串会被转换为浮点数,例如在执行算术运算时字符串"3.5"、"−4.01"、"4.2e6"、"−4.1 degree"分别被转换为浮点数3.5、−4.01、4200000、−4.1。如果字符串不是以数字开头,将被转换整数0,例如在执行算术运算时,字符串"Catch 22"将被转换为数整数0。例如,程序rules3.php如下。
(4)在进行字符串连接运算时,整数、浮点数将被转换为字符串类型数据。例如,12、12.3 转换为字符串后为"12"、"12.3"。布尔型TRUE将被转换成字符串"1",布尔型FALSE和NULL将被转换成空字符串"",这就解释了为何语句“echo TRUE;”打印到页面上为1,而语句“echo FALSE;”打印到页面上为空字符串。例如,程序rules4.php如下。
(5)在进行逻辑运算时,空字符串""、字符串"0"、整数0、浮点数0.0、NULL以及空数组将被转换为布尔型为FALSE,其他数据将被转换为布尔型TRUE(注意字符串"0.0"将被转换为布尔型TRUE)。例如,程序rules5.php如下。
3.5.2 强制类型转换
强制类型转换允许程序员手动将变量的数据类型转换成为指定的数据类型。PHP提供了以下3种强制类型转换方法。
(1)在要类型转换的变量或常量之前加上用括号括起来的目标数据类型。
(2)使用类型转换函数intval()、floatval()、strval()。
(3)使用通用类型转换函数settype()。
方法1 在变量前面加上一个小括号,并把目标数据类型填写在括号中。
这些目标数据类型包括:int、bool、float、string、array、object等。例如程序manual1.php如下。
<?php
$a = 11.2;
$b = (int)$a;
$c = (bool)$a;
$d = (float)$a;
$e = (array)$a;
$f = (object)$a;
$g = (string)$a;
var_dump($b); //输出:int(11)
echo "< br/>";
var_dump($c); //输出:bool(true)
echo "< br/>";
var_dump($d); //输出:float(11.2)
echo "< br/>";
var_dump($e); //输出:array(1) { [0]=> float(11.2) }
echo "< br/>";
var_dump($f);//输出:object(stdClass)#1 (1) { ["scalar"]=> float(11.2) }
echo "< br/>";
var_dump($g);//输出:string(4) "11.2"
?>
方法2 使用以val结尾的函数名的函数
如intval()、floatval() 、strval()函数,函数语法格式及功能如表3-9所示。例如,程序manual2.php如下。
<?php
$a = "123.9abc";
$b = intval($a);
$c = floatval($a);
$d = strval($a);
var_dump($b); //输出:int(123)
echo "< br/>";
var_dump($c); //输出:float(123.9)
echo "< br/>";
var_dump($d); //输出:string(8) "123.9abc"
?>
方法3 使用settype()函数
语法格式:bool settype ( mixed var, string type )
函数功能:设置变量var的数据类型为type数据类型,type的取值包括"bool"、"int"、"float"、"string"、"array"、"object"、"NULL"等字符串。函数如果执行成功则返回TRUE,否则返回 FALSE。例如,程序manual3.php如下。
<?php
$a = "123.9abc";
settype($a,"bool");
var_dump($a); //输出:bool(true)
echo "< br/>";
$b = "123.9abc";
settype($b,"int");
var_dump($b); //输出:int(123)
echo "< br/>";
$c = "123.9abc";
settype($c,"float");
var_dump($c); //输出:float(123.9)
echo "< br/>";
$d = "123.9abc";
settype($d,"string");
var_dump($d); //输出:string(8) "123.9abc"
echo "
";
$e = "123.9abc";
settype($e,"array");
var_dump($e); //输出:array(1) { [0]=> string(8) "123.9abc" }
echo "
";
$f = "123.9abc";
settype($f,"object");
var_dump($f);//输出:object(stdClass)#1 (1) { ["scalar"]=> string(8) "123.9abc" }
echo "< br/>";
$g = "123.9abc";
settype($g,"NULL");
var_dump($g); //输出:NULL
?>