PHP

www.LarryUllman.com

PHP标签内:

<?php

?>

echo ‘Hello, world!’;
echo “What’s new?”;
如果喜欢的话,可以代之以print():
print ‘Hello, world!’;
print “What’s new?”;

PHP具有8种变量。其中包括4种标量(单值)类型——布尔型(TRUE或FALSE)、整型、浮点型(小数)和字符串型(字符),两种非标量(多值)类型——数组和对象,以及资源(当与数据库交互时将看到它)和NULL(它是一种不具有任何值的特殊类型)。
不管创建什么类型,PHP中的所有变量都遵循某种特定的语法规则。
变量的名称——也称为它的标识符——必须以美元符号($)开头,例如,$name。
变量名称可以包含字母、数字和下划线的组合,例如,$my_report1。
美元符号之后的第一个字符必须是字母或下划线(不能是数字)。
PHP中的变量名称是区分大小写的。这是一个非常重要的规则。这意味着$name和$Name是截然不同的变量。
为了开始使用变量,我将利用几个预定义的变量,在运行PHP脚本时会自动设置它们的值。在深入介绍这个脚本之前,应该知道另外两件事情。第一,可以使用等于号(=)(也称为赋值运算符(assignment operator))给变量赋值。第二,无需引号即可打印变量:
print $some_var;
或者可以在双引号内打印变量:
print “Hello, $name”;
但不能在单引号内打印变量:
print ‘Hello, $name’; // Won’t work!

连接(concatenation)像是为字符串增加的一种功能,通过它把字符添加到字符串的末尾。可以使用连接运算符(concatenation operator)即句点(.)来执行它:
$city= ‘Seattle’;
$state = ‘Washington’;
$address = $city . $state;
$address变量的值现在是SeattleWashington,这几乎得到了期待的结果(Seattle, Washington)。为了对其进行改进,可以编写:
$address = $city . ‘, ‘ . $state;
从而将逗号和空格添加到字符串混合中。
连接还可以处理字符串或数字。下面两条语句将会产生相同的结果(Seattle, Washington 98101):
$address = $city . ‘, ‘ . $state . ‘ 98101’;
$address = $city . ‘, ‘ . $state . ‘ ‘ . 98101;

PHP具有许多专用于字符串的函数,你将在学习本书的过程中看到它们。例如,为了计算一个字符串有多长(它包含多少个字符),可以使用strlen():
$num = strlen(‘some string’); // 11

PHP可以利用几个函数转换字符串的大小写:strtolower(),把字符串全都变为小写;strtoupper(),把字符串全都变为大写;ucfirst(),第一个字符大写;ucwords(),每个单词的第一个字符大写。
如果只把一个值连接到另一个值,则可以使用连接赋值运算符(concatenation assignment operator)(.=)。下面两条语句是等价的:
$title = $title . $subtitle;
$title .= $subtitle;
本节开始的示例也可重写成:
$address = “$city, $state”;

$address = $city;
$address .= ‘, ‘;
$address .= $state;
使用PHP手册
在http://www.php.net/manual中可在线访问的PHP手册,列出了语言所有的函数和特性。该手册按照使用PHP的先后顺序进行组织,先讨论一般性概念(安装、语法、变量),最后是专题函数(MySQL、字符串函数等)。
要在PHP手册中快速查找函数,在浏览器中访问www.php.net/functionname(例如:http://www.php.net/print)。PHP手册为每个函数描述的内容如下:
函数有效的PHP版本;
函数的参数个数及类型(可选参数用方括号括起来);
函数的返回值类型。
手册还包含了每个函数的基本用法。
你应该养成查询PHP手册的好习惯。在遇到不熟悉的函数时,可以查询它的使用方法,还可以了解任何不明白的语言特性。更重要的是了解那些函数和特性的PHP版本,由于语言的发展,这些信息会不断地变化。

对数字除了可以使用标准的算术运算符(参见表1-1)之外,还可以使用许多函数。两个常用的函数是round()和number_format()。前者用于把小数四舍五入为最接近的整数:
$n = 3.14;
$n = round ($n); // 3
或者把小数四舍五入到指定的位数:
$n = 3.142857;
$n = round ($n, 3); // 3.143
表1-1 标准数学运算符
number_format()函数用于把一个数字转换成更常见的表示形式,用逗号作为千位分隔符,例如:
$n = 20943;
$n = number_format ($n); // 20,943
这个函数还可以设置小数点的指定位数:
$n = 20943;
$n = number_format ($n, 2); // 20,943.00

常量像变量一样,用于临时存储一个值,但是常量在许多方面与变量不同。对于初学者,要创建常量,可以使用define()函数,而不是赋值运算符(=)。
define (‘NAME’, value);
注意:一条经验法则是,全都使用大写字母来命名常量,尽管并非必须如此。最重要的是,常量不会像变量那样使用初始美元符号(因为严格说来常量不是变量)。
只能赋予常量一个标量值,比如字符串或数字:
define (‘USERNAME’, ‘troutocity’);
define (‘PI’, 3.14);
与变量不同的是,不能更改常量的值。
为了访问常量的值,比如当你想打印它时,不能用引号括住常量,比如:
echo “Hello, USERNAME”; // Won’t work!
对于这段代码,PHP只会打印出Hello,USERNAME(参见图1-18),而不会打印出USERNAME常量的值(因为没有美元符号告诉PHP,USERNAME是不同于字面量文本的任何内容)。可以代之以单独打印常量:
echo ‘Hello, ‘;
echo USERNAME;
或者使用连接运算符:
echo ‘Hello, ‘ . USERNAME;
PHP运行时利用了几个预定义的常量,这与本章前面使用的预定义变量非常相像。这些常量包括PHP_VERSION(PHP运行的版本)和PHP_OS(服务器的操作系统)。

在PHP中,理解单引号与双引号的区别是重要的。如迄今为止的示例中所示的那样,给字符串赋值时可以使用echo或print语句。但是,这两种引号之间以及何时该用哪种引号存在关键的区别。迄今为止,我详细说明了它们的区别,但是,现在将更明确地定义它们的使用模式。
在PHP中,括在单引号内的值将照字面意义进行处理,而括在双引号内的值将被解释。换句话说,把变量和特殊字符(参见表1-2)放在双引号内将导致打印出它们表示的值,而不是它们的字面量值。例如,假定你具有:
$var = ‘test’;
代码echo “var is equal to $var”;将打印出var is equal to test,而代码echo ‘var is equal to $var’;将打印出var is equal to $var。使用一个转义的美元符号,代码echo “\$var is equal to $var”;将打印出$var is equal to test,而代码echo ‘\$var is equal to $var’;将打印出\$var is equal to $var

对HTML表单进行详细讨论超出了本书的范围,但是,我们可以通过一个贯穿本章的HTML表单示例快速了解一下。如果你不熟悉HTML表单的基础知识,包括各种元素,可以查看HTML资源以了解更多信息。
HTML表单是使用form标签和多种用于获取输出的元素创建的。form标签看起来如下:

就PHP而言,form标签最重要的属性是action,它指定将把表单数据发送到哪个页面。第二个属性(method)需要进一步讨论(参见框注“选择方法”),但是,post是最常用到的值。
选择方法
表单的method属性指定如何把数据发送到处理页面。两个选项(get和post)指示要使用的HTTP(Hypertext Transfer Protocol,超文本传输协议)方法。get方法把提交的数据通过一系列追加到URL后面的名-值(name-value)对发送到接收页面。例如:
http://www.example.com/script.php?name=Homer&gender=M&age=35
使用get方法的好处是:可以在用户的Web浏览器中为得到的页面建立书签(因为它是一个URL)。因此,你还可以在Web浏览器中单击“后退”返回到一个get页面,或者重新加载它,而不会有任何问题(对于post,则不能执行这两种操作)。不幸的是,通过get传输的数据量有限,并且它不怎么安全(因为数据是可见的)。
一般来讲,get用于请求信息,比如数据库中的特定记录或者搜索的结果(搜索几乎总是使用get)。当需要采取一个动作时(比如在更新数据库记录或者发送电子邮件时),就使用post方法。由于这些原因,在全书中,我一般使用post,如果出现例外情况,我会另外指出。

16

17
18

Enter your information in the form below:

19
20

21
22

23
24

Male
Female

25
26

32
33

34
35

36
37

38
39

PHP的特性以及是什么使得它如此容易学习和使用,是它能够与HTML表单极好地进行交互。PHP脚本把接收到的信息存储在特殊的变量中。例如,假定你有一个表单,其中有一个输入,定义如下:

无论用户在该元素中输入什么内容,都可以通过一个名为$_REQUEST [‘city’]的PHP变量访问它。使拼写和大小写完全匹配非常重要,因为PHP对变量名区分大小写,因此$_REQUEST [‘city’]将会工作,但是$_Request [‘city’]或$_REQUEST [‘City’]将没有值。
$_REQUEST是一个特殊的变量类型,称为超全局(superglobal)变量。它存储了通过GET或POST方法发送到PHP页面的所有数据,以及在cookie中可访问的数据。在本章后面将讨论超全局变量。

PHP中条件为真的情况有许多种。下面是常见的一些:
$var,如果$var具有非0值、空字符串、FALSE或NULL,则条件为真;
isset($var),如果$var具有不同于NULL的任何值,包括0、FALSE或空字符串,则条件为真;
TRUE、true、True等。
在第二个示例中,引入了一个新函数isset()。这个函数用于检查一个变量是否被设置,这意味着它具有一个不同于NULL的值(提醒一下,在PHP中NULL是一种特殊类型,表示没有设置值)。

PHP用于创建条件语句的3个主要术语是:if、else和elseif(它也可以写作两个单词:else if)。每个条件语句都包含有一个if子句:
if (condition) {
// Do something!
}
if也可以有else子句:
if (condition) {
// Do something!
} else {
// Do something else!
}
elseif子句允许添加更多的条件:
if (condition1) {
// Do something!
} elseif (condition2) {
// Do something else!
} else {
// Do something different!
}

PHP还有另一种条件语句,称为switch,最适合代替较长的if-elseif-else条件语句。switch的语法是:
switch ($variable) {
case ‘value1’:
// Do this.
break;
case ‘value2’:
// Do this instead.
break;
default:
// Do this then.
break;
}
switch条件语句将$variable的值与不同的case作比较。当它发现一个匹配时,就会执行其后的代码,直至遇到break。如果没有发现匹配,则会执行default,假定存在default(它是可选的)。仅限于在可以检查变量值与某些情况的相等性的条件下使用switch条件语句,往往不能轻松地检查更复杂的条件语句。

验证表单数据需要使用条件语句以及许多函数、运算符和表达式。一个常用的标准函数是isset(),它用于测试一个变量是否具有值(包括0、FALSE,或者一个空字符串,但不能是NULL)。
使用isset()函数的一个问题是:空字符串测试为TRUE,这意味着它不是验证HTML表单中的文本输入和文本框的有效方式。要检查用户输入到文本元素中的内容,可以使用empty()函数。它将检查一个变量是否具有空(empty)值:空字符串、0、NULL或FALSE。
表单验证的第一个目标是确保在表单元素中输入或选择了某些内容。第二个目标是确保提交的数据具有正确的类型(数字、字符串等)、正确的格式(如电子邮件地址)或特定的可接受值(如$gender应该等于M或F)。因为PHP主要用于处理表单,所以在后续章节中将再度强调验证表单数据这一要点。但是,首先我将创建一个新的handle_form.php脚本,确保在引用变量之前,它们具有值。

要测试提交的值是否是数字,可使用is_numeric()函数。
在第14章中,你将看到如何使用正则表达式来验证表单数据。

PHP支持两种数组:索引数组(indexed array)和关联数组(associative array),前者使用数字作为键(如表2-3所示),后者使用字符串作为键(参见表2-4)。像在大多数编程语言中一样,索引数组的第一个索引开始于0,除非显式指定键。

数组遵守与任何其他变量相同的命名规则。因此,不能未经考虑地区分$var是数组,还是字符串或数字。访问各个数组元素时会显示重要的语法区别。
要从数组中检索特定的值,需要先引用数组变量名称,然后在方括号中指出键:
$band = $artists[0]; // The Mynabirds
echo $states[‘MD’]; // Maryland
可以像PHP中的其他值那样使用数组的键:数字(例如,2)永远不会用引号括住,而对字符串(MD)则必须这样做。
由于数组使用的语法不同于其他变量,对它们执行打印更具技巧性。首先,因为数组可以包含多个值,所以不能编写简单的代码打印它们(参见图2-16):
echo “My list of states: $states”;
图2-16 只通过引用数组名称来尝试打印一个数组将导致打印单词Array。

不过,如果使用索引(数字)键,那么打印各个元素的值将很简单:
echo “The first artist is $artists[0].”;
但是,如果数组使用字符串作为键,用于括住键的引号将使语法变得混乱。下面的代码将引发一个解析错误(参见图2-17):
echo “IL is $states[‘IL’].”; // BAD!
图2-17 由于没有使用花括号将要打印的数组元素括起来而出现的解析错误
为了解决这个问题,当数组使用字符串作为它的键时,把数组名和键包括在花括号中(参见图2-18)
echo “IL is {$states[‘IL’]}.”;
图2-18 使用花括号将要打印的数组元素括起来,会得到正确的结果
你觉得数组似乎有一点面熟,那是因为你已经使用过两个数组:$_SERVER(在第1章中)和$_REQUEST(在本章中)。为了让你熟悉另一个数组以及如何直接打印数组值,将使用更具体的$_POST数组创建基本的handle_form.php页面的修改版本(参见框注“超全局数组”)。
超全局数组
PHP默认包括多个预定义的数组。我曾经介绍过一些超全局(superglobal)变量:$_GET、$_POST、$_REQUEST、$_SERVER、$_ENV、$_SESSION和$_COOKIE。
PHP使用$_GET变量来存储通过get方法发送到PHP脚本的所有变量和值(它们可能来自于HTML表单,但不一定非得如此)。$_POST存储使用post方法从HTML表单发送到PHP脚本的所有数据。这两个变量以及$COOKIE变量都是你一直在使用的$_REQUEST变量的子集。
在第1章中使用的$_SERVER存储关于正在运行的服务器PHP的信息,就像$_ENV所做的那样。在第11章中将讨论$_SESSION和$_COOKIE。
良好的安全性与编程的一个方面在于精确地引用变量。这意味着尽管可以使用$_REQUEST访问通过post方法提交的表单数据,但是$_POST将更准确。

提示
由于PHP对其变量结构的要求很宽松,数组甚至可以使用数字和字符串的组合作为它的键。唯一重要的规则是数组的每一个键都必须是唯一的。
如果你发现访问超全局数组的语法令人感到糊涂(例如,$_POST[‘name’]),可以像你做过的那样在脚本顶部使用简写技术:
$name = $_POST[‘name’];
在这个脚本中,然后需要更改条件语句和echo语句来引用$name等变量。
在输出用字符串作为键的数组的值时,需要用花括号把数组括起来,以避免错误。下面示例使用的引号并没有问题,因此不需要花括号:
echo $_POST[‘name’];
echo “The first item is $item[0].”;
$total = number_format($cart[‘total’]);

在上一个示例中,我使用了PHP生成的数组,但是,你经常希望创建自己的数组。有两种主要方式可用于定义自己的数组。第一种方式是,可以一次添加一个元素来构建数组:
$band[] = ‘Jemaine’;
$band[] = ‘Bret’;
$band[] = ‘Murray’;
现在,$band[0]具有一个值Jemaine,$band[1]具有一个值Bret,$band[2]具有一个值Murray(由于数组的索引从0开始)。
此外,也可以在添加元素时指定键。但是,重要的是理解,如果指定一个键,并且已经存在用那个相同的键进行索引的一个值,则新值将重写现有的值。例如:
$band[‘fan’] = ‘Mel’;
$band[‘fan’] = ‘Dave’; // New value
$fruit[2] = ‘apple’;
$fruit[2] = ‘orange’; // New value
除了一次添加一个元素这种方式之外,也可以使用array()函数,只用一个步骤即可构建一个完整的数组:
$states = array (‘IA’ => ‘Iowa’, ‘MD’ => ‘Maryland’);
(因为PHP会忽略空格,你可以利用这个特性将代码分成多行,以便清晰明了。)
不论是否显式地设置了键,都可以使用array()函数:
$artists = array (‘Clem Snide’, ‘Shins’, ‘Eels’);
或者,如果你设置了第一个数字键值,那么此后添加的值将是可以递增的键:
$days = array (1 => ‘Sun’, ‘Mon’, ‘Tue’);
echo $days[3]; // Tue
在引用数组之前,也可使用array()函数初始化它:
$tv = array();
$tv[] = ‘Flight of the Conchords’;
在PHP中初始化数组(或者任何变量)不是必需的,但它可以使代码更清晰,并且有助于避免错误。
最后,如果你想创建连续数字的数组,那么可以使用range()函数:
$ten = range (1, 10);

你已经看到如何通过键(例如,$_POST[’email’])访问单个数组元素。当你确切知道键是什么或者如果你只想引用一个元素时,可以这样做。要访问每个数组元素,可以使用foreach循环:
foreach ($array as $value) {
// Do something with $value.
}
foreach循环将会迭代$array中的每个元素,并把每个元素的值赋予$value变量。要访问键和值,可以使用:
foreach ($array as $key => $value) {
echo “The value at $key is $value.”;
}
(你可以使用任何有效的变量名称代替$key和$value,如果你愿意,可以只使用$k和$v)。
我将说明使用数组来建立一组表单下拉菜单以从中选择一个日期有多容易(参见图2-21)。

在文本编辑器或IDE中创建一个新的PHP文档,命名为calendar.php

1
2
3
4
5 Calendar
6
7
8

9 ‘January’, ‘February’, ‘March’, ‘April’, ‘May’, ‘June’, ‘July’,
‘August’, ‘September’, ‘October’, ‘November’, ‘December’);
16
17 // Make the days and years arrays:
18 $days = range (1, 31);
19 $years = range (2011, 2021);
20
21 // Make the months pull-down menu:
22 echo ‘‘;
27
28 // Make the days pull-down menu:
29 echo ‘‘;
34
35 // Make the years pull-down menu:
36 echo ‘‘;
41
42 ?>
43

44
45

提示
要确定数组中元素的个数,可以使用count()函数。
$num = count($array);
range()函数也可以创建连续字母的数组:
$alphabet = range (‘a’, ‘z’);
数组的键可以是由多个单词组成的字符串,比如first name或phone
number。
is_array()函数可以确认一个变量是数组类型。
如果看到Invalid argument supplied for foreach()(为foreach()提供了无效的参数)出错消息,这意味着你正尝试在不是数组的变量上使用foreach循环。

最开始介绍数组时,我提到数组的值可以是数字、字符串甚至其他数组的任意组合。最后这种情况——包含其他数组的数组——将会创建一个多维数组(multidimensional array)。
多维数组比你所想的要普遍得多,但是,使用多维数组非常容易。例如,首先创建质数的数组:
$primes = array(2, 3, 5, 7, …);
然后创建楔形数的数组:
$sphenic = array(30, 42, 66, 70, …);
可以将这两个数组组合进一个多维数组中,如下:
$numbers = array (‘Primes’ => $primes, ‘Sphenic’ => $sphenic);
现在,$numbers是一个多维数组。要访问质数子数组,可以引用$numbers[‘Primes’]。要访问质数5,可以使用$numbers[‘Primes’][2](它是数组中的第三个元素,但是数组的索引从0开始)。要打印出这些值之一,可以用花括号包围整个构造:
echo “The first sphenic number is {$numbers[‘Sphenic’][0]}.”;
当然,你仍然可以使用foreach循环访问多维数组,如果需要的话,可把一个foreach循环嵌套在另一个内部。下一个示例就会这样做。
使用多维数组

35 // Combine the arrays:
36 $n_america = array(
37 ‘Mexico’ => $mexico,
38 ‘United States’ => $us,
39 ‘Canada’ => $canada
40 );
41
42 // Loop through the countries:
43 foreach ($n_america as $country => $list) {
44
45 // Print a heading:
46 echo “

$country

    “;
    47
    48 // Print each state, province, or territory:
    49 foreach ($list as $k => $v) {
    50 echo “

  • $k – $v
  • \n”;
    51 }
    52
    53 // Close the list:
    54 echo ‘

‘;
55
56 } // End of main FOREACH.

提示
多维数组也可以来自于HTML表单。例如,如果表单具有一系列名称为interests[]的复选框:
Music
Movies
Books
接收的PHP页面中的$_POST是多维的。$_POST[‘interests’]是一个数组,并用$_POST[‘interests’][0]存储第一个选中的复选框的值(例如,Movies),用$_POST[‘interests’][1]存储第二个选中的复选框的值(例如,Books),等等。注意:只会把选中的复选框传递到PHP页面。
如果HTML表单的选择菜单允许进行多重选择,也可以以多维数组结束:

同样,只会把所选的值传递到PHP页面。

数组和字符串
由于数组和字符串这两种变量类型是如此常用,以至于PHP具有两个函数,可以在字符串和数组之间相互进行转换。
$array = explode (separator, $string);
$string = implode (glue, $array);
使用和理解这两个函数的关键之处是分隔符(separator)和胶合(glue)关系。当把一个数组转变成一个字符串时,将会设置胶合——将被插入到生成字符串中的数组值之间的字符或代码。相反,当把字符串转变成数组时,要指定分隔符,它用于标记什么应该变成独立数组元素。例如,以字符串开始:
$s1 = ‘Mon-Tue-Wed-Thu-Fri’;
$days_array = explode (‘-‘, $s1);
$days_array变量现在是一个有5个元素的数组,其元素Mon的索引为0,Tue的索引为1,等等。
$s2 = implode (‘, ‘, $days_array);
$s2变量现在是一个用逗号分隔的一个星期中各天的列表:Mon, Tue, Wed, Thu, Fri。

数组排序
数组相对于其他变量类型的优点之一是,能够对它们进行排序。PHP包括多个可用于对数组排序的函数,它们的语法都很简单:
$names = array (‘Moe’, ‘Larry’, ‘Curly’);
sort($names);
这些排序函数执行3种排序。首先,可以使用sort()按值对数组排序,并丢弃原来的键。重要的是理解在排序过程之后将会重置数组的键,因此,如果键—值关系很重要,就不应该使用这个函数。
其次,可以使用asort()按值对数组排序,同时还会维持键。最后,可以使用ksort()按键对数组排序。如果把这些函数分别更改为rsort()、arsort()和krsort(),则能够以相反的顺序对数组排序。
为了演示对数组排序的作用,我将创建一个电影名称和评级(用1~10来评定我喜欢它们的程度)的数组,然后以不同的方式显示这个列表。

提示
要随机排列数组的顺序,可以使用shuffle()。
PHP的natsort()函数可用于以更自然的顺序对数组排序(主要是更好地处理字符串中的数字)。
PHP通过做一点工作可以对多维数组排序。见PHP手册,了解关于usort()函数的更多信息,或者查阅我的PHP 5 Advanced: Visual QuickPro Guide一书。

for和while循环
要讨论的最后一种语言构造是循环。我们在访问数组中的每个元素时,已经使用过一种循环,即foreach。下面你将使用的两种循环类型是for和while。
while循环看起来如下所示:
while (condition) {
// Do something.
}
只要循环的条件(condition)为真,就会执行循环。一旦条件为假,就会停止循环(参见图2-25)。如果条件永远不会为真,就永远不会执行循环。如你将在第8章中所看到的,当从数据库中检索结果时,最常使用while循环。
for循环具有更复杂的语法:
for (initial expression; condition;
closing expression) {
// Do something.
}
在第一次执行循环时,会运行初始表达式(initial expression)。然后检查条件,如果条件为真,就执行循环的内容。执行之后,将会运行结束表达式,并再次检查条件。这个过程会继续下去,直到条件为假(参见图2-26)。例如:
for ($i = 1; $i <= 10; $i+ +) { echo $i; } 17 // Make the months pull-down menu: 18 echo '‘;
23
24 // Make the days pull-down menu:
25 echo ‘‘;
30
31 // Make the years pull-down menu:
32 echo ‘‘;
37

PHP还有一个do…while循环,其语法稍微有所不同(查看手册)。这个循环总是会至少执行一次。
使用循环时,要注意观察参数和条件,避免可怕的无限循环,当循环条件永远不会为假时,就会发生这种情况。