第三章 PHP中的数据处理
本章着重讲述PHP程序的内部数据,包括数字,变量和常量。程序中的数据由操作符来控制的,操作符告诉PHP对内部数据进行什么操作(如加、减等等)。PHP程序的外部数据包括文本文件和数据库,对外部数据的详细介绍请参考第六章“数据库和SQL”
当程序运行时数值不会改变,这是因为这些数值在源代码中已经准确表示了它们该是什么值。而大多数时候,在程序运行时却需要改变某些数值,为此,必须留出一部分计算机的存储空间来保存可变化的数值。而且必须随时留意这些小存储单元的位置,以便程序能在需要时能找到它们。像所有计算机语言一样,PHP使用变量来监视计算机存储器的使用情况,每当需要存储一条新的消息时,就可以将它置成一个变量。常量指的是赋予一个名称的数值,最典型的一个常量例子就是数学值:π(pi)。
本章讲述了在PHP中如何使用数值、变量和常量。首先,我们先来讨论数值。
3.1 数值
数值常表示为“等于”或实际代码的形式,比如,在源代码程序中看到像12.5这样的数值时,它指的是十二点五,而不是指“1”,“2”,“.”,“5”这四个字符。可以用同样方式来表示文本,比如,“Rolf D"Barno”(注意双引号)表示由十二个字符组成的字符串。因为这十二个字符用双引号括了起来,因此,它们只能是一个字符串数值。
PHP使用两种类型的数值:
.数字 -- 最基本的数据类型。
.文本 -- 作为一个单元进行处理的一串字符。
3.1.1 数字
在PHP中最常使用的是数字,它通常代表为了完成某项任务而需要执行的程序所要用到的一个数值。我们最常使用的是十进制数,但在PHP中也可以使用八进制和十六进制。
在遇到很大的或很小的数字的时候,就会发现科学表达式是十分有用的了。在高中时我所学的数学知识差不多都快忘光了,只有对科学表达式牢记不忘,这大概是因为我比较喜欢移动小数点的缘故。科学表达式10.23E+4,等于102,300。也可以在科学表达式中用减号表示比较小的数,比如,10.23E-4等于.001023。简单地说,如果指数为正数的话,就将小数点向右移动,如果指数为负数,则将小数点向左移动。
注意:对于那些对非十进制不熟悉的人来说,这里有一个简单的解释。
十进制的基数为十。当看到值15时,它表示(1*10)+5或1510。下方的值代表基数。
八进制的基数为八。当看到值15时,它表示(1*8)+5或1310。
十六进制的基数为十六。当看到值15时,它表示(1*16)+5或2110。当基数为十六时,除了0到9外,还需要6个字符,以便能占满十六个值的每一个位置。字母A-F常用来表示11-16。因此,值BD16等于(B16*16)+D16或(1110*16)+1310,即17610。
让我们来看一看在程序中会用到的几种不同类型的数字。首先先来看整数。
* 123--十进制整数。
* 043--八进制整数,数字前缀0表示八进制数。
* 0x23--十六进制整数,数字前缀“0x”表示十六进制数。
有小数部分的数叫做浮点数。简略地讲,经常见到的那些数值指的都是浮点数。
* 100.5--有一位小数的一个浮点数,也可以称为一百又十分之五。
* 54.534--有三位小数的一个浮点数,也可以称为五十四又一千分之五百三十四。
* .000034--非常小的一个浮点数,也可以用科学表达式3.4E-5表示。
整数没有小数部分,浮点数有小数部分。
3.1.2 文本
文本是一组由引号括起来的字符,因而能被当为单个数据来使用。实际上,PHP对引号的要求并不严格,没有用引号括起来的单个词也可以用来表示字符串,但是为了避免混淆,请不要这样做。由于文本值包含有一系列字符,所以文本值通常称为字符串。它们在程序中常用于表示确定文件名、显示消息、输入提示等。PHP严格区分单引号(')、双引号(")和反引号(`)的作用。
文本也常称为字符串。
单引号字符串:
单引号字符串相当容易理解,只需要用单引号把想使用的文本括起来即可。例如:
'Men at Arms by Terry Pratchett'
'<p>This is an HTML paragraph.</p>'
单引号字符串是用单括号(')括起来的文本。
注意:读过本章后面的内容“变量替换”之后,单引号的真正作用才能表现出来。
如果需要在单引号内部再次使用单引号,事情就会变得有些麻烦。例如,下面的语句不能正常工作,这是由于第二个引号已经结束了所表示字符串。
'Terry's book is highly enjoyable.'
这个典型的错误即是语法(或分析)错误,PHP编译器不知道如何处理第二个单引号以后的文本。以下是正确的表示方式:
'Terry\'s book is highly enjoyable.'
反斜杠(\)字符串表示单引号的功能--结束文本值--将会被忽略。
提示:反斜杠字符也被称为转义字符,这也许是由于它使它后面的字符从常用含义中脱离出来的缘故。
有关单引号字符串的另一个更重要的要点是--如果需要在单引号字符串中换行,只要简单地在源代码中键入换行键即可。清单3.1显示了如何这样做。
清单3.1 line_breaks.php3--在输入行中加入换行即可开始新行
<?php
echo '<pre>First Paragraph:
Corporal Carrot, Ankh-Morpork City Guard
(Night Watch), sat down in his nightshirt
took up his pencil, sucked the end for a
moment, and then wrote:</pre>';
?>
如果读者不熟悉HTML语言的话,请阅读一到两本HTML教学指南。在本书以后的章节中必须熟悉HTML语言。
Page 35, 图 3。1
图 3.1 可以通过 Web浏览器看到在代码中加入的换行
在图3.1中可以看到用单引号括起来的,甚至在代码中包含换行的字符串的一部分。
双引号字符串:
双引号字符串类似于单引号字符串,但是双引号字符串更复杂一点。在双引号字符串中可以使用反斜杠在字符串中加入转义序列和转换字符。也可以使用变量替换,但是现在还不打算过早涉及有关变量替换方面的问题,这个主题留到以后再仔细讨论。
双引号字符串是由双引号(")括起来的字符串。
基本的双引号字符串是一系列由双引号(")括起来的字符,如果需要在字符串中使用双引号,可以使用反斜杠字符。例如:
"Men at Arms by Terry Pratchett"
"<p>This is an HTML paragraph.</p>"
"Terry's book is highly enjoyable. "
"John said,\"Gifts are great.\""
注意在最后一行中的反斜杠用来使双引号的功能改变,如果不使用反斜杠字符,也可以使用单引号。双引号字符串和单引号字符串的一个较大的不同之处是,双引号字符串可以在字符串中加入特殊的转义序列。表3.1显示了PHP可以理解的转义序列。
表3.1 转义序列
转义序列 描述
\n 换行
\r 回车
\t 制表符
\$ 美圆符号
\0nnn 任一个八进制数
\xnn 任一个十六进制数
\\ 反斜杠字符
提示:在下一节“变量”中,就可以知道在使用$字符时,为什么需要使用反斜杠。
你也许对\0nnn和\xnn比较陌生,请看下面的例子:
"Peter was \067 years old yesterday."
"Peter was \0x39 years old yesterday. "
以上的文本都表示彼得 9岁了,八进制和十六进制序列都表示彼得的岁数9这个字符的ASCII代码。ASCII代码的清单详见附录B。
反引号字符串:
对于反引号字符串是否是真正的文本还存在争论,这是因为PHP使用反引号字符串来运行系统命令。当PHP看到反引号字符串时,它将字符串数值传递给Windows、UNIX或者用户使用的其他类型操作系统。清单3.2显示了这个过程是如何完成的,图3.2显示在Web浏览器窗口中的系统命令输出结果。
反引号字符串使用反引号(`)括起来。
清单3.2 back_quoted_string.php3--使用反引号字符串执行命令
<?php
echo '<pre>';
echo `ls *.php3`;
echo '</pre>';
?>
Page 37 图3.2
图3.2在Web浏览器中显示的系统命令所显示的文本
在双引号字符串使用的转义序列也能在反引号字符串中使用。
3.2 变量
数字仅能解决用来程序当中的内部数据的一部分问题。当需要保存数据值,并在运行程序时需要进行改变的时候,就需要用到变量。PHP有三种类型的变量:
标量 -- 一次保存一个特定数字或字符串。我通常用scl_作为标量名的起始字符。如果该变量只保存一种类型的值时,我将在其名字前使用int_或str_前缀。
数组 -- 存储数值的列表。这些数值可能是数字、字符串或是另一个数组。我通常用arr_作为数组变量的起始字符。
对象 -- 存储变量信息和函数。更详细的信息请参看第十章“面向对象”。我通常用obj_作为对象变量的起始字符。
提示:推荐对不同类型的数据使用可区分的变量名,除非有更好的理由。如果需要使用同一个名字的时候,可以尝试使用名字的复数作为数组变量名。例如,使用 $name作为标量名,并使用$names作为数组变量名。这将在以后的编程中避免一些混乱。
注意:在PHP中的变量名是区分大小写的。这意味着$scl_varname、$scl_Valname、$scl_varName和$scl_VARNAME都代表不同的变量。
在本章下面的部分将分别讨论每一种变量类型。你将读到如何命名变量、设置它的值、以及它们的一些用处。
3.2.1 标量
标量常用来跟踪单个信息。例如,客户的名字或出售的数量。只要标量名以$为第一个字符,第二个字符是字母或下划线,就可以使用任一个可以从名字想象出是什么东西的名字作为标量名。
提示:如果曾经使用Visual Basic进行过编程,那么在命名变量时必须特别小心。要记住所有的标量名都是以$为开始的,而不只是字符串;名字的开始字符是$,而不是名字的结尾字符是$。
让我们现在看看一些变量的名字:
* $int_page_number--存储当前页码。
* $str_magazine_title--存储杂志的标题。
* $0--无效的变量名字。变量名不能以数字字符开始。
我较喜欢使用具有描述能力的变量名。对我来说,$int_book_number比$booknum更好,这是由于$int_book_number的描述性更好。由于较长的文件名有助于理解程序,因此在程序不使用比较短的变量名较好。PHP变量名的长度实际上没有什么限制,但是我一般把长度限制到二十个字符以内。比二十个字符还长的名字,有可能增加产生拼写失误的机会。
使用具有描述性的名字:int_book_number比booknum更好。
明白了什么是标量名之后,现在让我们看看如何给变量赋值。对一个标量赋值通常使用等号,如以下清单3.3所示。
清单3.3 assign_scalars.php3--使用赋值操作符
<?PHP
$int_page_number=46;
$str_magazine_title = 'PHP is good!';
?>
以上代码给变量赋值。当给变量赋给简单的文本值时,由于使用单符号字符串效率更高,所以通常使用单符号字符串。
注意:PHP使用双斜杠(//)来作为注释的开始,在双斜杠字符后面的任何字符都会被忽略。
对变量赋值以后,可以根据需要改变它们的值。下一个例子,清单3.4,先对一个变量赋值,然后使用第二次赋值来改变变量的值。第二次赋值使原有的数值加一。
清单3.4 change_scalars.php3--改变变量的值
<?PHP
$int_page_number = 46;
$int_page_number =$int_page_number +1;
?>
注意:在PHP编程中,永远不必声明、定义或分配简单的数据类型(标量或数组),第一次使用变量名就相当于定义它。
3.2.2 数组变量
一个数组就是把一系列数字和字符串作为一个单元来处理。数组中的每一片信息都被认为是数组的一个元素。例如,可以用数组存储一个文件中的所有行或者存储一个地址列表。
只要不用数字作为数组变量名的第一个字符,而且在创建数组名时只使用数字、字母和下划线的时候,就不必操心数组变量的命名规则。
数组元素有三种方法设置初始值,可以对每一个元素分别赋值:
$arr_zoo['pelican'] = 'Bird with a big beak, ';
$arr_zoo['cheetah'] = 'Fast cat. ';
$arr_zoo['horse'] = 'Four-legged animal. ';
也可以用下面的方法同时对多个元素赋值:
$arr_zoo = arry(
'pelican' => 'Bird with a big beak. '
, 'cheetah'=> 'Fast cat. '
, 'horse' => 'Four-legged animal. '
);
最后,最快的方法是简单在数组的下一个空余位置上增加一个元素,第一个位置是0,第二个位置是1,依次类推。例如,下面的代码给$arr_names数组增加了三个元素,这三个元素的下标分别为1、2和3(假设这个数组没有其它元素存在)。
$arr_names[] = 'Mitch';
$arr_names[] = 'Gerry';
$arr_names[] = 'Tim';
在知道了如何给数组元素赋值之后,下一步让我们讨论一下如何如何获取这些值。
为了得到数组名为arr_zoo,且数组下标为'pelican'的值时,可以使用以下方法:
$key = 'pelican'
$value = $arr_zoo[$key]
这两行代码运行以后,$value的值变为'bird with a big beak'。文本字符串也可以用来指定要哪一个数组元素的值。例如:
$value = $arr_zoo[pelican];
用于数组下标的字符值不应该用单引号括起来(Perl称它们为裸词)。由于可以使用裸词,数组下标中不应该有空格。
注意:当读取一个并没有赋值的数组元素时,PHP返回空或零字符串。
PHP数组的数组下标和数组值是成对出现的,由于没有一个很方便的方法显示数组中的所有值,这个事实偶尔会引起一些麻烦。在测试和调试程序阶段中,这种功能性的缺乏可能会妨碍程序的开发。虽然本书中还没有提及这些函数,清单3.5提供了一个这样的函数。现在只要把dump_array函数当成黑箱子即可,等读完本书后,就会明白此函数的含义。把这个例子当成模板,程序中的注释说明了如何使用这个函数。图3.3显示了使用dump_array函数的结果。
清单3.5 dump_array.php3--改变变量的值
Page 42, 清单 3.5
注意:dump_array函数没有按特殊的顺序显示数组下标和数组值对。第四章讨论了可以对数组进行排序的函数。
Page 43,图3.3,
图3.3 dump_array函数显示任一个数组的数组下标和值
以上我们只采用了字符串作为数组下标,让我们思维更活跃一点,考虑一下下面所创建的数组初始值的数组下标是什么?
$arr_mixed = array(
1
,434
, 'Jake' => '23 First Lane'
, 'Rebecca'
);
arry_mixed数组的数组下标分别是0、1、Jake和2。如果数组下标没有给定,PHP就自动提供一个。默认的数组下标是以0开始的,以后当数组下标没有赋值时默认值每次加一。
可以用标量变量替换所有的数值下标(数字和字符串),并仍能获取它们原有的值。可以这样写:
$key = 1;
echo $arr_mixed[$key];
以上两行将显示434,让我们用这个例子显示PHP是如何按照需要,而把数字数据类型转换成字符数据类型的。在以下的代码行中,数组下标被初始化成字符串:
$key = '1';
echo $arr_mixed[$key];
这两行代码也显示434,表明了PHP可以自动地把字符串转换成数值。
有时,可能需要在数组初始化过程中使用变量。例如:
$int_page_number = 434;
$str_first_name = 'Jake';
$arr_mixed = array(
1
,$int_page_number
,$str_first_name => '23 First Lane'
,'Rebecca'
);
3.2.3 多维数组
对于大多数程序来说,仅有一个简单的数值列表是很不够的。例如,假如既要存书的总页数,又要存储出版商的名字。这需要使用两个列表:lst_number_of_pages和lst_publisher_names,在需要增加或修改信息的时候,就很不方便了。并且保证两个列表的同步也留下了隐患。
多维数组提供了一个极灵活的数据结构,每一个数组元素均可以包含另外一个数组。遗憾的是,多维数组(multidimensional)名字实在太长--我更喜欢称它为散列表,它体现了在存贮器中数据结构是如何组织的。
注意:我不打算详细讲述散列表的数据结构是怎样有效的使用存储空间,以及它为什么能快速找到域值。不过,如果你有兴趣的话,我建议阅读一本数据结构方面的书,以便进一步学习。
散列表可以按以下格式进行初始化:
$arr_books = array(
'0-679-76781-9' => array(
'name' => 'The Demolished Man'
,'pages' => 243
,'publisher' => 'Vintage Books'
)
, '0-312-85395-5' => array(
'name' => 'Children of the Mind'
, 'pages' => 349
, 'publisher' => 'Tor Books'
)
);
在上例中使用了每本书的ISBN号作为检索数组$arr_books的散列表下标,且每本书都有它自己的子散列表,用以描述其自己的特定信息。为了查询子散列表中的信息,正常的数组下标被扩展为采用两个下标,例如:要查《The Demolished Man》一书的页数有多少,可以用以下的表达式
$arr_books[0-31-85395-5][pages]
你会发现散列表十分灵活方便。毫不夸张地说,在我写的每一个程序中都会使到散列表。之所以这样,其中一个很重要的原因就是散列表使用起来是如此的灵活,以至于随时都可以加入需要的元素。假如在程序运行过程中,你觉得应该将作者名也存进去的话,那么没有问题,只需简单的在散列表中加入如下信息:
$arr_books[0-312-85395-5][author] = 'Orson Scott Card'。
注意散列表数据结构允许在一个子散列表中加入一项内容,而不会影响其它数据。当开始使用PHP从多个数据库表中收集信息时,散列表能用来组合这些信息。例如,当使用一个涉及到多个产品供应商的产品数据库时,可以从第一个产品供应商开始将相关信息存入散列表中。然后,再读取第二个产品供应商的信息,并将这些新信息写入同一个散列表中。将所有产品供应商信息读取、并全部写入散列表以后,这一个散列表就包含了所有的货存信息。
在前面给出的3.5列表中的函数dump_array,阐明了散列表的组织结构。图3.4显示了使用dump_array函数解释的散列表$arr_books的组织结构。
Page 46, 图3.4
图3.4 使用dump_arry函数显示的散列表
3.2.4 变量替换
双引号字符串还有一个特性,由于涉及到变量,我们以前还没有讨论。既然现在我们已经对PHP变量是如何工作的已经很熟悉了,让我们再进一步讨论一下双引号字符串。
变量替换 意味着PHP可以用在双引号字符串中变量的值替换其名字,把这个概念延伸到通常含义即是变量代表了它们的值。例如,如果$int_count为14,那么$int_count + 14就真正是14 + 14。PHP,以及大多数计算机语言,这种替换是在字符串内完成的。例如:
$str_size = 'big';
echo "Jack was a $str_size man. ";
将显示
Jack was a big man.
但是,如果需要在变量后面立即跟随非空格或非标点符号外的其它字符时,就会出现问题。以下代码段显示了这是如何发生的:
$str_size = 'big';
echo "Jack was a $str_sizeger man. ";
PHP不会寻找后面跟有字符串('ger')的变量($str_size),而是寻找变量名为$str_sizeger的变量。把变量名用大括号括起来可以解决这个问题:
$str_size = 'big';
echo "Jack was a ${str_size}ger man. ";
在使用过变量替换多次之后,字符串和变量的组合就变的很自然。清单3.6显示了一些变量替换的例子。
清单3.6 interpolation.php3--变量替换的例子
Page 47 第7行= Page 48 第13行 清单 3.6
图3.5显示了散列表$arr_books有三级组成,第三级包含有书籍的名称。正常情况下可以用类似下面的方式访问散列表的命名元素:
echo "The name is
$arry_books[lst_books][0-679-76781-9][name].";
// The previous line of code produces a PHP parse error.
Page 48 图3.5
图3.5 使用标量和数组变量进行变量替换
然而不幸的是,当使用变量替换时,PHP3不允许同时使用多于一个的数组下标。PHP的安全存取书籍名的方法如下:
$second_level = $arr_books[lst_books];
$third_levwl = $second_level[0-679-76781-9];
echo "The name is $third_level[name].";
3.2.5 动态变量名
PHP允许用户动态的创建变量名。当程序运行时,使用特殊的符号可以创建新的变量名:
// store the name of the dynamic variable.
$scl_dynamic = 'str_name';
// assign a value to the dynamic variable.
$$scl_dynamic = 'John';
echo "\$str_name = $str_name\n";
此程序将显示
$str_name =John
尽管动态变量名存在一些吸引使用的方面,但是我在二十年的编程经历中,从没有发现有使用它们的需要。数组的灵活性应该足以解决大多数有可能需要使用动态变量名的问题。
3.3 常量
常量可以帮助你以一种简单的方法使程序增加可读性。使用BUFFER_SIZE比直接使用1024使程序更容易让人理解。此外,由于大多数常量都在程序文件的开头部分定义,对它们进行更改也非常容易。
可以同时定义数字常量和字符串常量。在以下的例子显示了如何这样做:
<?php
define('PI', 3.1415);
define('HOST', '192.168.0.2');
?>
除了不需要在常量名前加$符号外,存取常量值和存取变量值非常类似。在上面定义的两个常量可以用如下的方式存取:
echo 'PI = ' . PI;
echo 'HOST = ' . HOST;
因为不使用初始的$符号,所以变量替换并不适合常量。
3.4 操作符
操作符指挥计算机应该进行什么操作。我们可以这样理解操作符,就好比你在向汽车司机发布“左转”或“右转”的命令。这些命令可以认为是方向操作符,与进行加或减操作的数学操作符有同样的操作方式。然而在另一方面,在汽车行驶时对司机大喊“