2007-04-19
版权 © 1997-2007 PHP 文档组
版权信息
© Copyright 1997 - 2007 PHP 文档组版权所有。发布本资料须遵守开放出版许可协议 1.0 或者更新版本。一份开放出版许可协议的拷贝已随本手册发布,其最新版本位于 http://www.opencontent.org/openpub/。
未经版权所有者明确授权,禁止发行本文档被实质上修改的版本。
未经版权所有者事先授权,禁止将此作品及其衍生作品以标准(纸质)书籍形式发行。
如果有兴趣再发行或再版本手册的全部或部分内容,不论修改过与否,或者有任何问题,请联系版权所有者 doc-license@lists.php.net。注意本地址映射到一个公开归档的邮件列表。
本手册中 Zend API 一章是根据 Zend Technologies 提供的内容而来。
本手册主要由函数参考组成,但也包括语言参考,PHP 一些主要特点的说明以及其它补充信息。
可以在 http://www.php.net/download-docs.php 下载本手册的数种格式。关于本手册如何被开发的更多信息,请参阅附录:“关于本手册”。如果对 PHP 的历史感兴趣,请访问相关附录。
欢迎加入 PHP 简体中文翻译小组!具体加入方法请访问此页面,点击该页面右上角的“下载”以取得该 howto 文档的最新版本并仔细阅读。
手册首页仅突出了目前最活跃的人员,但是还有更多的贡献者在现在或者过去对本项目提供了大量的帮助。很多不留名的人也帮忙在手册中写下了笔记,并不断被包括在手册中,也很感谢他们的工作。下面的姓名列表按照字母顺序排列。
下列人员曾经或者目前正在为本手册添砖加瓦: Jouni Ahto, Alexander Aulbach, Daniel Beckham, Stig Bakken, Jesus M. Castagnetto, Ron Chmara, Sean Coates, John Coggeshall, Simone Cortesi, Markus Fischer, Wez Furlong, Sara Golemon, Rui Hirokawa, Brad House, Pierre-Alain Joye, Etienne Kneuss, Moriyoshi Koizumi, Rasmus Lerdorf, Andrew Lindeman, Hannes Magnusson, Stanislav Malyshev, Rafael Martinez, Yasuo Ohgaki, Derick Rethans, Rob Richards, Sander Roobol, Egon Schmid, Thomas Schoefbeck, Sascha Schumann, Dan Scott, Masahiro Takagi, Michael Wallner, Lars Torben Wilson, Jim Winstead, Jeroen van Wolffelaar 和 Andrei Zmievski.
下列人员对本手册做出了重大的编辑工作: Stig Bakken, Gabor Hojtsy, Hartmut Holzgraefe 和 Egon Schmid.
目前最活跃的维护者是: Mehdi Achour, Friedhelm Betz, Etienne Kneuss, Nuno Lopes, Hannes Magnusson, Bobby Matthis 和 Philip Olson.
下列人员为维护用户评论作出了巨大的努力: Daniel Beckham, Victor Boivie, Jesus M. Castagnetto, Nicolas Chaillan, Ron Chmara, Sean Coates, James Cox, Vincent Gevers, Sara Golemon, Zak Greant, Szabolcs Heilig, Oliver Hinckel, Hartmut Holzgraefe, Rasmus Lerdorf, Matthew Li, Andrew Lindeman, Aidan Lister, Maxim Maletsky, James Moore, Sebastian Picklum, Derick Rethans, Sander Roobol, Damien Seguy, Jason Sheets, Maciek Sokolewicz, Tom Sommer, Jani Taskinen, Yasuo Ohgaki, Jakub Vrana, Lars Torben Wilson, Jim Winstead, Jared Wyles 和 Jeroen van Wolffelaar.
PHP(“PHP: Hypertext Preprocessor”,超文本预处理器的字母缩写)是一种被广泛应用的开放源代码的多用途脚本语言,它可嵌入到 HTML中,尤其适合 web 开发。
以上是一个简单的回答,不过这是什么意思呢?请看如下例子:
请注意这个范例和其它用 C 或 Perl 语言写的脚本之间的区别――与用大量的命令来编写程序以输出 HTML 不同的是,我们用 PHP 编写了一个 HTML 脚本,其中嵌入了一些代码来做一些事情(例如,在本例中输出了一些文本)。PHP 代码被包含在特殊的起始符和结束符中,使得可以进出“PHP 模式”。
和客户端的 JavaScript 不同的是,PHP 代码是运行在服务端的。如果在服务器上建立了如上例类似的代码,则在运行该脚本后,客户端就能接收到其结果,但他们无法得知其背后的代码是如何运作的。甚至可以将 web 服务器设置成让 PHP 来处理所有的 HTML 文件,这么一来,用户就无法得知服务端到底做了什么。
使用 PHP 的一大好处是它对于初学者来说极其简单,同时也给专业的程序员提供了各种高级的特性。当看到 PHP 长长的特性列表时,请不要害怕。可以很快的入门,只需几个小时就可以自己写一些简单的脚本。
尽管 PHP 的开发是以服务端脚本为目的,但事实上其功能远不局限与此。请继续读后面的章节,在“PHP 能做什么”一节中将获得更多的信息。如果对 web 编程感兴趣,也可以阅读简明教程。
PHP 能做任何事。PHP 主要是用于服务端的脚本程序,因此可以用 PHP 来完成任何其它的 CGI 程序能够完成的工作,例如收集表单数据,生成动态网页,或者发送/接收 Cookies。但 PHP 的功能远不局限于此。
PHP 脚本主要用于以下三个领域:
服务端脚本。这是 PHP 最传统,也是最主要的目标领域。开展这项工作需要具备以下三点:PHP 解析器(CGI 或者服务器模块)、web 服务器和 web 浏览器。需要在运行 web 服务器时,安装并配置 PHP,然后,可以用 web 浏览器来访问 PHP 程序的输出,即浏览服务端的 PHP 页面。如果只是实验 PHP 编程,所有的这些都可以运行在自己家里的电脑中。请查阅安装一章以获取更多信息。
命令行脚本。可以编写一段 PHP 脚本,并且不需要任何服务器或者浏览器来运行它。通过这种方式,仅仅只需要 PHP 解析器来执行。这种用法对于依赖 cron(Unix 或者 Linux 环境)或者 Task Scheduler(Windows 环境)的日常运行的脚本来说是理想的选择。这些脚本也可以用来处理简单的文本。请参阅 PHP 的命令行模式以获取更多信息。
编写桌面应用程序。对于有着图形界面的桌面应用程序来说,PHP 或许不是一种最好的语言,但是如果用户非常精通 PHP,并且希望在客户端应用程序中使用 PHP 的一些高级特性,可以利用 PHP-GTK 来编写这些程序。用这种方法,还可以编写跨平台的应用程序。PHP-GTK 是 PHP 的一个扩展,在通常发布的 PHP 包中并不包含它。如果对 PHP-GTK 感兴趣,请访问其网站以获取更多信息。
PHP 能够用在所有的主流操作系统上,包括 Linux、Unix 的各种变种(包括 HP-UX、Solaris 和 OpenBSD)、Microsoft Windows、Mac OS X、RISC OS 等。今天,PHP已经支持了大多数的 web 服务器,包括 Apache、Microsoft Internet Information Server(IIS)、Personal web Server(PWS)、Netscape 以及 iPlant server、Oreilly Website Pro Server、Caudium、Xitami、OmniHTTPd 等。对于大多数的服务器,PHP 提供了一个模块;还有一些 PHP 支持 CGI 标准,使得 PHP 能够作为 CGI 处理器来工作。
综上所述,使用 PHP,可以自由地选择操作系统和 web 服务器。同时,还可以在开发时选择使用面对过程和面对对象,或者两者混和的方式来开发。尽管 PHP 4 不支持 OOP 所有的标准,但很多代码仓库和大型的应用程序(包括 PEAR 库)仅使用 OOP 代码来开发。PHP 5 弥补了 PHP 4 的这一弱点,引入了完全的对象模型。
使用 PHP,并不局限于输出 HTML。PHP 还能被用来动态输出图像、PDF 文件甚至 Flash 动画(使用 libswf 和 Ming)。还能够非常简便的输出文本,例如 XHTML 以及任何其它形式的 XML 文件。PHP 能够自动生成这些文件,在服务端开辟出一块动态内容的缓存,可以直接把它们打印出来,或者将它们存储到文件系统中。
PHP 最强大最显著的特性之一,是它支持很大范围的数据库。用户会发现利用 PHP 编写数据库支持的网页简单得难以置信。目前,PHP 支持如下数据库:
同时还有一个 DBX 扩展库使得可以自由地使用该扩展库支持的任何数据库。另外,PHP 还支持 ODBC,即 Open Database Connection Standard(开放数据库连接标准),因此可以连接任何其它支持该世界标准的数据库。
Adabas D InterBase PostgreSQL dBase FrontBase SQLite Empress mSQL Solid FilePro(只读) Direct MS-SQL Sybase Hyperwave MySQL Velocis IBM DB2 ODBC Unix dbm Informix Oracle(OCI7 和 OCI8) Ingres Ovrimos
PHP 还支持利用诸如 LDAP、IMAP、SNMP、NNTP、POP3、HTTP、COM(Windows 环境)等不计其数的协议的服务。还可以开放原始网络端口,使得任何其它的协议能够协同工作。PHP 支持和所有 web 开发语言之间的 WDDX 复杂数据交换。关于相互连接,PHP 已经支持了对 Java 对象的即时连接,并且可以将他们自由的用作 PHP 对象。甚至可以用我们的 CORBA 扩展库来访问远程对象。
PHP 具有极其有效的文本处理特性,支持从 POSIX 扩展或者 Perl 正则表达式到 XML 文档解析。为了解析和访问 XML 文档,PHP 4 支持 SAX 和 DOM 标准,也可以使用 XSLT 扩展库来转换 XML 文档。PHP 5 基于强健的 libxm2 标准化了所有的 XML 扩展,并添加了 SimpleXML 和 XMLReader 支持,扩展了其在 XML 方面的功能。
如果将 PHP 用于电子商务领域,会发现其 Cybercash 支付、CyberMUT、VeriSign Payflow Pro 以及 MCVE 函数对于在线交易程序来说是非常有用的。
另外,还有很多其它有趣的扩展库。例如 mnoGoSearch 搜索引擎函数、IRC 网关函数、多种压缩工具(gzip、bz2)、日历转换、翻译……
由于在这里无法列出 PHP 所有的特性和可提供的便利,请参阅安装以及函数参考有关章节以获取关于这里提到的扩展库更多的信息。
本章将给出关于 PHP 的简明教程。虽然 PHP 的功能并不局限于生成动态的 web 页面,但本章的内容仅涉及于此。请查阅“PHP 能做什么”一节以获取更多信息。
使用了 PHP 的 web 页面将被和通常的 HTML 页面一样处理,可以用通常建立 HTML 页面的方法来建立和编辑它们。
在本教程中,假设用户的服务器已经安装并运行了 PHP,所有以 .php 结尾的文件都将由 PHP 来处理。在大部分的服务器上,这是 PHP 的默认扩展名,不过,也请询问服务器管理员以确认。如果服务器支持 PHP,则不需要做任何事情。只用建立 .php 文件,并把它们放置到 web 目录中,服务器将神奇地自动解析这些文件。不用编译任何东西,也不用安装任何其它的工具,仅仅只需把这些使用了 PHP 的文件想象成简单的 HTML 文件,其中只不过多了一种新的标识符,在这里可以做各种各样的事情。大多数的 web 主机都提供 PHP 的支持,如果你的主机不支持,可以访问 PHP 相关链接来查找支持 PHP 的 web 主机。
假设用户希望在本地机器开发以节约宝贵的带宽。在这种情况下,需要安装一个诸如 Apache 的 web 服务器,当然还有 PHP。可能还希望安装一个数据库,例如 MySQL。
可以一个个的安装它们或选择一个更简单的方法。可以参考本手册中 PHP 安装说明的相关章节(假设已经配置好了某个 web 服务器)。若在自己安装 PHP 时出现了问题,建议在安装邮件列表中询问。如果想使用更简便的方法安装 PHP,那么可以考虑获取一个预先配置的安装包,用这个安装包,只用点击几下鼠标,就可以自动地安装所有这些系统。在任何操作系统下建立有 PHP 支持的 web 服务器都十分简单,包括 MacOSX、Linux 和 Windiws。在 Linux 下,会发现 rpmfind 和 PBone 能够在获取 RPM 时提供帮助。也可以使用 apt-get 搜索 Debian 的相关软件包。
在 web 服务器根目录(DOCUMENT_ROOT)下建立一个文件名为
hello.php,然后完成如下内容:
该程序非常的简单,它仅仅只是利用了 PHP 的 echo() 语句显示了 Hello World。用户一定不会满足与此。请注意该文件无需被执行或以任何方式指定。服务器会找到该文件并提供给 PHP 进行解释,因为使用了“.php”的扩展名,服务器已被配置成自动传递有着“.php”扩展名的文件给 PHP。一个普通的 HTML 文件,加上了几个特别的标签,就可以做很多非常有趣的事情!
如果试过了这个例子,但是没有得到任何输出,或者浏览器弹出了下载框,或者浏览器以文本方式显示了源文件,可能的原因是服务器还没有支持 PHP,或者没有正确配置。需要请服务器的管理员根据本手册“安装”一章的内容使得服务器支持 PHP。如果本地开发,请阅读手册有关安装的章节以确保所有的设置都正确。还要确认通过浏览器访问的 URL 确实指向了服务器上的这个文件。如果只是从本地文件系统调用这个文件,它不会被 PHP 解析。如果问题仍然存在,请通过 PHP 在线支持中的各种方式获取帮助。
以上例子的目的是为了显示 PHP 特殊标识符的格式。在这个例子中,用 <?php 来表示 PHP 标识符的起始,然后放入 PHP 语句并通过加上一个终止标识符 ?> 来退出 PHP 模式。可以根据自己的需要在 HTML 文件中像这样开启或关闭 PHP 模式。请参阅手册中“PHP 基本语法”以获取更多信息。
关于换行: 尽管换行在 HTML 中的实际意义不是很大,但适当地使用换行可以使 HTML 代码易读且美观。PHP 会在输出时自动删除其结束符 ?> 后的一个换行。该功能主要是针对在一个页面中嵌入多段 PHP 代码或者包含了无实质性输出的 PHP 文件而设计,与此同时也造成了一些疑惑。如果在 PHP 结束符 ?> 后输出换行的话,可以在其后加一个空格,或者在最后的一个 echo/print 语句中加入一个换行。
关于文本编辑器: 有很多文本编辑器以及集成开发环境(IDE)可以被用来建立、编辑和管理 PHP 文件。这些工具中的一部分被列在 PHP 编辑器列表中。如果希望推荐其它的编辑器,请访问以上页面,并要求该页面的维护者将你推荐的编辑器加入到该列表中。使用支持语法高亮功能的编辑器会给开发带来很多帮助。
关于文字处理器: 诸如 StarOffice Writer、Microsoft Word 和 Abiword 的文字处理器不适合用来编辑 PHP 程序。如果希望用以上这些工具的某一种来处理脚本,必须保证将结果存成了纯文本格式,否则 PHP 将无法读取并运行这些脚本。
关于 Windows 记事本: 如果使用 Windows 记事本来编写 PHP 脚本,需要注意在保存文件时,文件的后缀名应该为 .php(记事本将自动在文件名后面加上 .txt 后缀,除非采取以下措施之一来避免这种情况)。当保存文件时,系统会让你指定文件的文件名,这时请将文件名加上引号(例如 "hello.php")。或者,也可以点击“保存”对话框中的“保存类型”下拉菜单,并将设置改为“所有文件”。这样在输入文件名的时候就不用加引号了。
现在已经成功建立了一个简单的 PHP 脚本。还可以建立一个最著名的 PHP 脚本。调用函数 phpinfo(),将会看到很多有关自己系统有用的信息,以及预定义变量、已经加载的 PHP 模块和配置信息。请花一些时间来查看这些重要的信息。
现在来编写一些更实用的脚本,比如检查浏览页面的访问者在用什么浏览器。要达到这个目的,需要检查用户的
agent 字符串,它是浏览器发送的 HTTP 请求的一部分。该信息被存储在一个变量中。在 PHP
中,变量总是以一个美元符开头。我们现在感兴趣的变量是
$_SERVER['HTTP_USER_AGENT']。
注意: $_SERVER 是一个特殊的 PHP 保留变量,它包含了 web 服务器提供的所有信息,被称为超全局变量。请查阅本手册“超全局变量”中的有关内容以获取更多信息。这些特殊的变量是在 PHP 4.1.0 版本引入的。在这之前使用
$HTTP_*_VARS数组,如$HTTP_SERVER_VARS。尽管现在已经不用了,但它们在新版本中仍然存在(参见“旧代码”一节中的注解)。
要显示该变量,只需简单地进行如下操作:
PHP 有很多种不同类型的变量。在以上例子中我们打印了一个数组的单元。数组是一类非常有用的变量。
$_SERVER 只是 PHP 自动全局化的变量之一。可以查阅“保留变量”一节来查看这些变量的列表,或者也可以通过上节例子中
phpinfo() 函数的输出来查看。
可以在一个 PHP 标识中加入多个 PHP 语句,也可以建立一个代码块来做比简单的 echo 更多的事情。例如,如果需要识别 Internet Explorer,可以进行如下操作:
这里要介绍一些新的原理。上面用了一个 if 语句。如果用户对 C 语言的基本语法比较熟悉,则应该对此很熟悉,否则,可能需要拿起任何一本 PHP 介绍性的书籍并阅读前面的两三个章节,或者也可以阅读本手册的“语言参考”一章。
需要介绍的第二个原理,是对 strpos()
函数的调用。strpos() 是 PHP
的一个内置函数,其功能是在一个字符串中搜索另外一个字符串。例如我们现在需要在
$_SERVER['HTTP_USER_AGENT'](即所谓的 haystack)变量中寻找
'MSIE'。如果在这个 haystack
中该字符串(即所谓的 needle)被找到,则函数返回 needle
在 haystack 中相对开头的位置;如果没有,则返回 FALSE。如果该函数没有返回
FALSE,则 if 会将条件判断为
TRUE 并运行其花括号 {} 内的代码;否则,则不运行这些代码。可以自己尝试利用
if,else 以及其它的函数,例如
strtoupper() 和
strlen(),来建立类似的脚本。在本手册中相关的页面也包含有范例。如果对如何使用函数不是很确定,可以阅读手册中有关“如何阅读函数定义”和“函数”的有关章节。
以下我们进一步显示如何进出 PHP 模式,甚至是在一个 PHP 代码块的中间:
例 2-5. 混和 HTML 和 PHP 模式
该脚本的输出可能是:
|
和以上我们用一个 PHP 的 echo 语句来输出不同的是,我们跳出了 PHP 模式来直接写 HTML 代码。这里很值得注意的一点是,对于这两种情况而言,脚本的逻辑效率是相同的。在判断了 strpos() 函数的返回值是 TRUE 或是 FALSE,也就是判断了字符串 'MSIE' 是否被找到之后,最终只有一个 HTML 块被发送给浏览者。
PHP 一个很有用的特点体现在它处理 PHP 表单的方式。需要理解的非常重要的原理,是表单的任何元素都在 PHP 脚本中自动生效。请参阅本手册中“PHP 的外部变量”以获取关于在 PHP 中使用表单的详细信息及范例。以下是 HTML 表单的范例:
该表单中并没有什么特殊的地方,其中没有使用任何特殊的标识符。当用户填写了该表单并点击了提交按钮,页面 action.php 将被调用。在该文件中,可以加入如下内容:
Apart from the htmlspecialchars() and
(int) parts, it should be obvious what this does.
htmlspecialchars() makes sure any characters that
are
special in html are properly encoded so people can't inject HTML tags
or Javascript into your page. For the age field, since we know it is
a
number, we can just convert
it to an integer which will automatically get rid of any
stray characters. You can also have PHP do this for you automatically
by
using the filter extension.
PHP
将自动设置 $_POST['name'] 和
$_POST['age'] 变量。在这之前我们使用了超全局变量
$_SERVER,现在我们引入了超全局变量
$_POST,它包含了所有的
POST 数据。请注意我们的表单提交数据的方法(method)。如果使用了
GET 方法,那么表单中的信息将被储存到超全局变量
$_GET
中。如果并不关心请求数据的来源,也可以用超全局变量
$_REQUEST,它包含了所有
GET、POST、COOKIE 和 FILE 的数据。请参阅
import_request_variables() 函数。
也可以在 PHP 中处理 XForms 的输入,尽管可能更喜欢使用长久以来支持良好的 HTML 表单。XForms 目前还不适合初学者使用,但是用户可能对它感兴趣。手册中在“特点”一章有一节对如何处理从 XForum 接收到的数据进行了简短的介绍。
现在,PHP 已经发展成为一种流行的脚本语言,可以在很多公共的资源里找到可以在自己的脚本中重新利用的代码。PHP 语言的开发者为向下兼容性下了很多功夫,因此在新版本的 PHP 下,老版本的代码应该可以在不作任何改动的情况下(理想地)运行。不过实际上,还是必须对老的代码做一些改动。
有可能影响到老版本的代码的最重要的两点改动分别是:
取消了旧的 $HTTP_*_VARS
数组(在函数或者方法中原本是全局变量)。PHP
4.1.0
版本引入了如下超全局数组变量:$_GET、$_POST、$_COOKIE、$_SERVER、$_FILE、$_ENV、$_REQUEST
以及 $_SESSION。老的 $HTTP_*_VARS
数组,诸如 $HTTP_POST_VARS 等,从 PHP 3 就已经开始使用,它们仍然存在。自 PHP 5.0.0 起,长格式的 PHP
预定义变量可以通过设置
register_long_arrays 来屏蔽。
外部变量不再被默认注册为全局变量。也就是说,从
PHP 4.2.0
版开始,php.ini 中的设置选项
register_globals
默认值变成了
off。建议用以上提到的超全局数组变量来访问这些值。但可能老的脚本、书籍以及教程都可能建立在该设置为
on 的基础上。如果该选项被设置为
on,则可以在
URL http://www.example.com/foo.php?id=42
中直接使用变量 $id。但不管被设置为 on 还是
off,$_GET['id'] 一直有效。
如果希望了解关于这些改动的细节,请参阅“预定义变量”一章以及其中的连接。
用现在掌握的知识,应该能够理解本手册中的大部分内容以及其中各式各样的脚本范例。在 php.net 网站的连接区 http://www.php.net/links.php 能购获得其它更多的范例。
请查阅 PHP Conference 资料网站 http://conf.php.net/ 及 http://talks.php.net/ 以观看更多幻灯片,这些幻灯片展示了许多 PHP 其它的功能。
安装前,首先需要知道想用 PHP 来做什么。PHP 主要用在三个领域,分别在“PHP 能做什么”一节中进行了描述:
网站和 web 应用程序(服务器端脚本)
命令行脚本
桌面(GUI)应用程序
在通常情况下,需要三样东西:PHP 自身、一个 web 服务器和一个 web 浏览器。可能已经有了一个 web 浏览器,并且根据操作系统的配置,也很可能已经有了一个 web 服务器(例如 Linux 和 MacOS 下的 Apache;Windows 下的 IIS)。也许在某个公司租用了 web 空间,这样,自己无需设置任何东西,仅需要编写 PHP 脚本,并上传到租用的空间中,然后在浏览器中查看结果。
如果需要自己配置服务器和 PHP,有两个方法将 PHP 连接到服务器上。对于很多服务器,PHP 均有一个直接的模块接口(也叫做 SAPI)。这些服务器包括 Apache、Microsoft Internet Information Server、Netscape 和 iPlanet 等服务器。其它很多服务器支持 ISAPI,即微软的模块接口(OmniHTTPd 就是个例子)。如果 PHP 不能作为模块支持 web 服务器,总是可以将其作为 CGI 或 FastCGI 处理器来使用。这意味着可以使用 PHP 的 CGI 可执行程序来处理所有服务器上的 PHP 文件请求。
如果对 PHP 命令行脚本感兴趣(例如在离线状态下,根据传递给脚本的参数,自动生成一些图片,或处理一些文本文件),总是需要命令行可执行程序。更多信息可以参考 PHP 的命令行模式。如果是这种情况,不需要服务器和浏览器。
还可以用 PHP 的 PHP-GTK 扩展来编写桌面图形界面应用程序。这与编写 web 页面完全不同,因为无需输出任何 HTML,而要管理窗口和窗口中的对象。关于 PHP-GTK 的更多信息,请访问专门为该扩展建立的网站。PHP-GTK 没有包含在官方发布的 PHP 中。
现在,本节开始说明如何在 Unix 和 Windows 的 web 服务器中配置服务器模块接口和 CGI 可执行程序。也将在下面几节中了解到有关命令行可执行程序安装的信息。
PHP 源代码包和二进制包可以在 http://www.php.net/downloads.php 找到。建议选择一个最近的镜象服务器下载。
本节将指导如何在 Unix 系统下安装和配置 PHP。在开始安装之前,请务必研究自己使用的系统和 web 服务器的相关章节。
在安装前需要考虑的事项一节提到,在本节主要以 web 为中心介绍 PHP 的设置。不过本节也会覆盖一些 PHP 命令行用法的设置方法。
在 Unix 平台下安装 PHP 有几种方法:使用配置和编译过程,或是使用各种预编译的包。本文主要针对配置和编译 PHP 的过程。很多 Unix 类系统都有包安装系统,可以用它来设置一个有着标准配置的 PHP。但是若需要与标准配置不同的功能(例如一个安全服务器,或者不同的数据库驱动扩展模块),可能需要编译 PHP 和/或 web 服务器。如果不熟悉编译软件,可以考虑搜索一下是否有人已经编译了包含所需要功能的预编译包。
编译所需的知识和软件:
基础的 Unix 技能(有能力操作“make”和一种 C 语言编译器)
一个 ANSI C 语言编译器
flex:版本 2.5.4
bison:版本 1.28(推荐)、1.35 或 1.75
一个 web 服务器
模块特别需要的组件(例如 gd、pdf 库等)
PHP 初始的配置和安装过程被 configure 脚本中一系列命令行选项控制。可以通过 ./configure --help 命令了解 PHP 所有可用的编译选项及简短解释。本手册是分开对这些选项编写文档的。可在附录中找到核心配置选项,而扩展模块特定的配置选项分别在其函数参考页面中描述。
配置好 PHP 后,便可以开始编译模块和/或可执行文件。make 命令用来做这一工作。如果该命令执行失败而找不到原因,请参考安装问题一节。
本节包括在 Unix 平台的 Apache 下安装 PHP 的说明和提示。我们在另外的页面也有 Apache 2 的安装和说明。
可以从核心配置选项列表以及位于手册对应部分的特定扩展配置选项中选择参数并在安装步骤第 10 步将它们添加到 configure 命令中。版本号在这里被省略了以保证此说明的正确性。需要将这里的“xxx”替换为自己使用的文件的正确值。
例 4-1. PHP 的 Apache 共享模块版本安装说明
|
也可以将 PHP 作为静态对象来安装:
例 4-2. PHP 的 Apache 静态模块版本安装说明
|
注意: 对于 PHP 4,把 php-5 换成 php-4,把 php5 换成 php4。
根据 Unix 系统和 Apache 安装方法的不同,有很多方法停止和重启动 Apache。以下是一些不同的 Apache/UNIX 下重启动 Apache 的典型命令。需要把 /path/to/ 替换成自己系统上的确切路径。
例 4-3. 重启动 Apache 的示例命令
|
apachectl 和 http(s)dctl 程序所在的路径在不同系统中通常不一样。如果系统中有 locate 或者 whereis 或者 which 命令,那么可以帮助找到这些控制程序。
编译 PHP 和 Apache 的不同例子还有:
此配置将生成在 Apache 的 httpd.conf 文件中用 LoadModule 加载的 libphp5.so 共享库(PHP 4 是 libphp4.so)。而 PostgreSQL 支持将嵌入到此共享库中。
此配置将生成 Apache 的 libphp5.so 共享库,并且还生成 pgsql.so 共享库,可以在 php.ini 文件中用 extension 指令加载,或者在 PHP 脚本中用 dl() 函数明确地加载。
此配置将生成 libmodphp5.a 库,mod_php5.c 和一些相关的文件并且拷贝到 Apache 源程序目录中的 src/modules/php5 目录下。然后用 --activate-module=src/modules/php5/libphp5.a 编译 Apache,Apache 编译系统会生成 libphp5.a 并且将其静态地连接到 httpd 程序中(在 PHP 4 中把 php5 替换成 php4)。PostgreSQL 支持也直接包括在这个 httpd 程序中了,因此最终结果是单一的一个包括了所有 Apache 和 PHP 支持的 httpd 可执行文件。
此配置和上面一样――除了没有在最后的 httpd 可执行文件中包括 PostgreSQL 的支持以及生成了一个 pgsql.so 共享库以外。该共享库可以在 php.ini 文件中或者用 dl() 函数加载。
当选择不同的方法编译 PHP 时,需要考虑每种方法的优势和缺点。用共享对象方式编译 PHP 意味着可以单独编译 Apache,并且不用在添加或修改了 PHP 的时候重新编译所有程序。用内置方法编译 PHP(静态方式)意味着 PHP 可以加载和运行得更快。更多信息见 Apache 的 DSO 支持页面。
注意: Apache 默认的 httpd.conf 文件中目前包括类似如下的内容:
除非把它修改成“Group nogroup”或者其它类似的(“Group daemon”也很通用),PHP 将不能打开文件。
注意: 确认在使用
--with-apxs=/path/to/apxs时指向 Apache 安装后的目录中的 apxs。绝对不能用 Apache 源程序中的 apxs 而要用安装后的 apxs。
本节包括在 Unix 平台的 Apache 2.0 下安装 PHP 的说明和提示。
| 警告 |
不推荐将线程化 MPM 用于实际运作的 Apache 2 环境中去。用 prefork MPM 替代,或者用 Apache 1。其原因见 FAQ 中的使用线程化 MPM 的 Apache2。 |
推荐阅读 Apache 文档,了解一下 Apache 2.0 服务器。
PHP 和 Apache 2.0.x 兼容性注意事项: 已知下列版本的 PHP 可以工作于最近版本的 Apache 2.0.x 之下:
以上版本的 PHP 与 Apache 2.0.40 或更高版本兼容。
- PHP 4.3.0 或更高版本,可从 http://www.php.net/downloads.php 下载。
- 最新的稳定开发版。取得源代码 http://snaps.php.net/php5-latest.tar.gz 或下载 Windows 可执行程序 http://snaps.php.net/win32/php5-win32-latest.zip。
- 预发布版,可从 http://qa.php.net/ 下载。
- 总是可以通过匿名 CVS 取得 PHP。
Apache 2.0 SAPI 支持自 PHP 4.2.0 起。PHP 4.2.3 可工作于 2.0.39,不要用任何其它版本的 Apache 与 PHP 4.2.3 配合。不过推荐的设置是用 PHP 4.3.0 或更高版本与最新版的 Apache2 配合使用。
所有提及的 PHP 版本仍然能工作于 Apache 1.3.x 之下。
下载最新版本的 Apache 2.0,并且根据上文选择合适版本的 PHP 下载。本向导仅包含最基础的内容,只能让 Apache 2.0 和 PHP 能够正常工作。更多信息请阅读 Apache 文档。这里省略所有的版本号,以保证本文的正确性。需要将本文的“NN”替换为相应的版本号。
例 4-4. 安装说明(Apache 2 共享模块版本)
|
按照上面的步骤便可以使 Apache 2.0 将 PHP 作为 SAPI
模块了。当然 Apache 和 PHP 都还有很多配置选项,可以在相应的源代码目录中使用
./configure --help 获得更多信息。假如要编译一个多线程版本的
Apache 2.0,必须覆盖标准的 MPM-Module prefork,或者
worker 或者 perchild。要这样,需要在上面的第
6 步使用 --with-mpm=worker 或者
--with-mpm=perchild
选项。之前需要了解自己在做什么。更多信息请参考 Apache 文档中关于
MPM-Modules 的部分。
注意: 如果要使用内容协商(content negotiation)机制,请阅读 Apache MultiViews 常见问题。
注意: 要编译多线程版本的 Apache,系统必须支持多线程。这也意味着需要将 PHP 编译为正处在试验阶段的 Zend Thread Safety(ZTS),因此并不是所有的扩展都可以使用了。推荐编译 Apache 使用标准的 prefork MPM-Module。
PHP 4 可以被编译为 Caudium web 服务器的一个 Pike 模块。注意 PHP 3 中不支持。请参考下面的安装说明以将 PHP 4 安装到 Caudium 服务器中。
例 4-5. Caudium 安装指南
|
当然可以将各种 PHP 4 的扩展模块编译到 Caudium 服务器中。请参考扩展库各自配置选项的说明。
注意: 当编译 PHP 4 的 MySQL 的支持时,必须确认使用了正常的 MySQL 客户端代码。否则如果 Pike 已经支持 MySQL,就会产生冲突。应该在编译的时候使用
--with-mysql选项指定 MySQL 的安装目录。
要将 PHP 作为 fhttpd 的模块来编译,在提示“Build as an fhttpd module?”时,回答“yes”(用 --with-fhttpd=DIR 来配置)并且指定 fhttpd 源代码的基本目录。默认的目录是 /usr/local/src/fhttpd。如果正在使用 fhttpd 服务器,将 PHP 编译成模块方式将提供更好的性能,更多的可控性以及远程执行能力。
注意: PHP 4.3.0 以后的版本已经不再提供对 fhttpd 的支持。
本节包含了在 Sun Solaris 平台的 Sun Java System web Server、Sun ONE web Server、iPlanet 和 Netscape 下安装 PHP 的说明和提示。
从 PHP 4.3.3 起,可以使用基于 NSAPI 模块 PHP 脚本来生成自定义目录列表和错误页面。更多与 Apache 兼容的功能也可以使用。要了解如何在当前的 web 服务器中支持此功能,请阅读关于子请求(subrequests)的注释。
可以在下面的链接中了解更多关于在 Netscape Enterprise Server(NES)中设置 PHP 的信息:http://benoit.noss.free.fr/php/install-php4.html。
要在 Sun JSWS/Sun ONE WS/iPlanet/Netscape web 服务器中编译 PHP,请为 --with-nsapi=[DIR] 输入合适的安装目录。默认的目录通常是 /opt/netscape/suitespot/。还可以阅读 /php-xxx-version/sapi/nsapi/nsapi-readme.txt。
从 http://www.sunfreeware.com/ 或其它下载站点安装下面的软件包:
| autoconf-2.13 |
| automake-1.4 |
| bison-1_25-sol26-sparc-local |
| flex-2_5_4a-sol26-sparc-local |
| gcc-2_95_2-sol26-sparc-local |
| gzip-1.2.4-sol26-sparc-local |
| m4-1_4-sol26-sparc-local |
| make-3_76_1-sol26-sparc-local |
| mysql-3.23.24-beta(如果想要 mysql 支持) |
| perl-5_005_03-sol26-sparc-local |
| tar-1.13 (GNU tar) |
请确认 PATH 变量包含适当的目录 PATH=.:/usr/local/bin:/usr/sbin:/usr/bin:/usr/ccs/bin,并使用 export PATH 命令将其导出为环境变量。
gunzip php-x.x.x.tar.gz(如果使用 .gz 版本,否则跳到 4)
tar xvf php-x.x.x.tar
进入 PHP 解压缩后的目录:cd ../php-x.x.x
在下面的步骤中,请确认 Netscape 服务器安装在 /opt/netscape/suitespot/ 目录中。否则,将下面命令中的该路径修改为正确的路径并运行:
./configure --with-mysql=/usr/local/mysql \ --with-nsapi=/opt/netscape/suitespot/ \ --enable-libgcc |
运行 make,然后运行 make install。
在执行了基础的安装并阅读相应的 Readme 文件后,还需要执行一些额外的配置步骤。
Sun/iPlanet/Netscape 的配置说明.
首先需要为 LD_LIBRARY_PATH
环境变量添加一些路径,以便服务器找到所需的共享库。可以使用 web
服务器的启动脚本很好的完成这一工作。启动脚本通常位于:/path/to/server/https-servername/start。或许需要编辑其配置文件,它位于:/path/to/server/https-servername/config/。
添加下面一行到 mime.types(可以在管理服务器中添加):
type=magnus-internal/x-httpd-php exts=php |
编辑 magnus.conf( 若服务器 >= 6)或 obj.conf(若服务器 < 6)并添加下述内容。shlib 的值根据系统的配置会有所不同。它可能类似于 /opt/netscape/suitespot/bin/libphp4.so。应该在 mime types init 后添加如下两行内容:
Init fn="load-modules" funcs="php4_init,php4_execute,php4_auth_trans" shlib="/opt/netscape/suitespot/bin/libphp4.so" Init fn="php4_init" LateInit="yes" errorString="Failed to initialize PHP!" [php_ini="/path/to/php.ini"] |
在 obj.conf 中配置默认对象(对于虚拟服务器的类 [版本 6.0+] 是在 vserver.obj.conf 中):
<Object name="default"> . . . .#注意 下面一行添加在所有“ObjectType”之后,所有“AddLog”之前 Service fn="php4_execute" type="magnus-internal/x-httpd-php" [inikey=value inikey=value ...] . . </Object> |
本步骤仅在需要配置一个由 PHP 脚本组成的目录时由必要执行(类似于一个 cgi-bin 目录):
<Object name="x-httpd-php"> ObjectType fn="force-type" type="magnus-internal/x-httpd-php" Service fn=php4_execute [inikey=value inikey=value ...] </Object> |
认证的设置:PHP 认证不能与其它任何类型的认证一起工作。所有认证被传递到 PHP 脚本。要为整个服务器配置 PHP 认证,在默认对象中添加下面一行:
<Object name="default"> AuthTrans fn=php4_auth_trans . . . </Object> |
要在单一目录使用 PHP 认证,添加如下内容:
<Object ppath="d:\path\to\authenticated\dir\*"> AuthTrans fn=php4_auth_trans </Object> |
注意: PHP 使用的堆栈大小取决于 web 服务器的配置。如果运行很大的 PHP 脚本时程序崩溃,推荐在 Admin Server(在“MAGNUS EDITOR”一节)中增大此项。
当编写 PHP 脚本时,应特别注意 Sun JSWS/Sun ONE WS/iPlanet/Netscape 是一个多线程 web 服务器。因此,所有请求都运行在相同的进程空间(Web 服务器自己的空间),该空间仅有一套环境变量。如果想获得 CGI 变量,例如 PATH_INFO、HTTP_HOST 等,使用原有的 PHP 3.x 的方式(getenv()),或使用类似的方式(注册全局变量到环境变量, $_ENV),都是不可行的。只能获得运行中的 web 服务器的环境变量,而不能获得任何有效的 CGI 变量!
注意: 为什么在环境中存在(无效的)CGI 变量?
答:这是因为从管理服务器中启动 web 服务器进程时,运行了 web 服务器的启动脚本,它事实上是一个 CGI 脚本(管理服务器中的一个 CGI 脚本!)。这便是为什么启动的 web 服务器包含一些 CGI 变量。可以尝试不从管理服务器启动 web 服务器,用 root 用户登录使用命令行手动启动它,会发现这些 CGI 形式的变量不复存在。
要在 PHP 4.x 中正确获得 CGI 变量,仅需修改脚本使用超级全局变量 $_SERVER。如果老脚本中使用了 $HTTP_HOST 等变量,应该在 php.ini 中打开 register_globals,并且要修改变量顺序(注意:从中删除 "E",因为不需要这里的环境变量):
variables_order = "GPCS" register_globals = On |
可以使用 PHP 为 "404 Not Found" 或类似的错误代码生成错误页面。将下面几行添加到 obj.conf 中以覆盖默认的错误页面:
Error fn="php4_execute" code=XXX script="/path/to/script.php" [inikey=value inikey=value...] |
另一种可能是生成自造目录列表。只要创建一个 PHP 脚本,来显示目录列表 并在 obj.conf 中为 type="magnus-internal/directory" 将相应的默认 Service 行替换为:
Service fn="php4_execute" type="magnus-internal/directory" script="/path/to/script.php" [inikey=value inikey=value...] |
NSAPI 模块现在支持 nsapi_virtual() 函数(别名:virtual()),用来在 web 服务器上创建子请求(subrequests)和在 web 页面插入请求的结果。此函数使用了一些 NSAPI 中还没有文档说明的函数。在 Unix 下,该模块自动查找需要的函数,若它们存在则使用它们。若不存在,函数 nsapi_virtual() 被禁用。
注意: 但是要注意,对 nsapi_virtual() 的支持是试验性质的!
默认为将 PHP 编译为 CGI 程序。这将建立一个命令行解释器,可用于 CGI 处理或非 web 相关的 PHP 脚本。如果用户运行着一个 PHP 模块支持的 web 服务器,那通常为性能考虑应该使用模块方式。不过,CGI 版可以使 Apache 用户用不同的用户 ID 运行不同的 PHP 页面。
| 警告 |
如果使用 CGI 方式安装,则服务器对于某些可能的攻击是开放的。请阅读 CGI 安全一章以学习如何防御这些攻击。 |
自 PHP 4.3.0 起,PHP 有了一些重要的新增功能。又有了一个新的 SAPI 称为 CLI,和 CGI 程序同名。根据配置选项它安装在 {PREFIX}/bin/php,并在手册中 PHP 的命令行模式一章中有详细说明。更多细节请阅读该章节。
如果将 PHP 3 编译为 CGI 程序,可以通过键入 make bench 来进行一下性能的基准测试。注意如果默认打开了安全模式,则超过 30 秒的允许范围测试可能不能完成。这是因为 set_time_limit() 不能用于安全模式。用 max_execution_time 配置选项来为你自己的脚本控制此时间限制。make bench 会忽略配置文件。
注意: make bench 仅能用于 PHP 3。
某些服务器提供的环境变量没有定义在当前的
CGI/1.1 标准中。只有下列变量定义在其中:AUTH_TYPE,CONTENT_LENGTH,CONTENT_TYPE,GATEWAY_INTERFACE,PATH_INFO,PATH_TRANSLATED,QUERY_STRING,REMOTE_ADDR,REMOTE_HOST,REMOTE_IDENT,REMOTE_USER,REQUEST_METHOD,SCRIPT_NAME,SERVER_NAME,SERVER_PORT,SERVER_PROTOCOL
和 SERVER_SOFTWARE。其它的变量均作为“供应商扩展(vendor extensions)”来对待。
本章节的内容和提示仅限于将 PHP 安装到 HP-UX 系统上(此文章是由 paul_mckay at clearwater-it dot co dot uk 编写的)。
注意: 本文涉及的技巧适用于 PHP 4.0.4 和 Apache 1.3.9。
安装 PHP 需要一个 gzip,可以从如下地址得到该软件的二进制版本的发行包 http://hpux.connect.org.uk/ftp/hpux/Gnu/gzip-1.2.4a/gzip-1.2.4a-sd-10.20.depot.Z,下载后解压缩,并且使用 swinstall 安装。
安装 PHP 需要 gcc,可以从如下地址得到该软件的二进制版本的发行包 http://gatekeep.cs.utah.edu/ftp/hpux/Gnu/gcc-2.95.2/gcc-2.95.2-sd-10.20.depot.gz,解压缩这个文件,使用 swinstall 安装 gcc。
安装 PHP 需要 GNU binutils,可以从如下地址得到该软件的二进制版本的发行包 http://hpux.connect.org.uk/ftp/hpux/Gnu/binutils-2.9.1/binutils-2.9.1-sd-10.20.depot.gz,解压缩这个文件,使用 swinstall 安装 binutils。
安装 PHP 需要 bison,可以从如下地址得到该软件的二进制版本的发行包 http://hpux.connect.org.uk/ftp/hpux/Gnu/bison-1.28/bison-1.28-sd-10.20.depot.gz,安装方式同上。
安装 PHP 需要 flex,需要从 http://www.gnu.org 的镜像站点下载一个该软件的源代码。它被放置于一个 非 gnu 目录的 ftp 服务器上。下载这个文件,并且使用 gunzip 解压缩,然后执行 tar -xvf。进入新创建的 flex 目录并运行 ./configure,再执行 make 以及 make install。
如果这里出现了错误,很可能是由于 gcc 等工具不在路径中,应将其添加到环境变量 PATH 中。
下载 PHP 和 apache 的源代码。
下载后对他们分别执行 gunzip 和 tar -xvf。在开始编译他们之前我们需要修改一些文件。
首先 configure 文件需要被修改,因为它似乎忘记自己是在 hpux 系统下了,有更好的方法解决此问题,但最省事的是在配置脚本的第 47286 行加入 lt_target=hpux10.20。
其次是修改 Apache GuessOS 文件。在文件 apache_1.3.9/src/helpers 的第 89 行,将参数 echo "hp${HPUXMACH}-hpux${HPUXVER}"; exit 0 替换为 echo "hp${HPUXMACH}-hp-hpux${HPUXVER}"; exit 0。
不能把 PHP 作为共享对象方式安装到 HP-UX, 因此你必须将其编译成为一个静态方式,参照 Apache 站点的指导就可以完成。
这样就完成了 PHP 和 Apache 的 安装编译,然而 Apache 将仍然不能启动,必须为 Apache 配置一个新的用户名,例如 www 或 apache。然后修改 Apache 配置文件 conf/httpd.conf 的 252 和 253 行,由原来的
User nobody Group nogroup |
替换为类似如下的内容
User www Group sys |
这是因为在 hp-ux 系统下, Apache 不能作为 nobody 用户运行。按照上面的方式配置 Apache 和 PHP 就应该可以正常工作了。
本章节的内容和提示仅限于将 PHP 安装到 OpenBSD 3.6 系统上。
使用二进制包安装 PHP 到 OpenBSD 系统上是被推荐的同时也是最简单的方法。PHP 核心包已经从其他模块中分离出来了并且每个模块可以被独立的安装/卸载而不影响其他模块。所有这些安装 PHP 需要的文件可以在 OpenBSD 光盘或者在 FTP 站点上找到。
需要安装的 PHP 核心包的文件是 php4-core-4.3.8.tgz,它包含了基本的引擎(包括 gettext 和 iconv)。其次,可能还需要安装一些模块包,如:php4-mysql-4.3.8.tgz 或 php4-imap-4.3.8.tgz。需要使用命令 phpxs 去激活它,并且再通过修改 php.ini 文件来屏蔽他们。
例 4-6. 在 OpenBSD 系统下的软件包的安装示例
|
阅读用户手册中的 packages(7) 部分,可以得到更多 OpenBSD 系统下有关二进制软件包的信息.
同样可以使用软件包目录(ports tree)来编译 PHP 的源代码。然而,这样的安装方式仅仅是建议对 OpenBSD 非常熟悉的高级用户去做。PHP4 的软件包被分别分为了两个子目录:core 和 extensions。其中 extensions 目录产生了所有 PHP 所支持的子模块。如果不希望创建并且使用这些模块中的某些模块,请使用 FLAVOR no_* 参数。例如,如果希望跳过编译 imap 模块,设置 FLAVOR 为 no_imap 即可。
默认安装的 Apache 运行于 chroot(2) jail,将限制 PHP 脚本只能访问 /var/www 下面的文件。需要建立 /var/www/tmp 目录来存放 PHP session 文件,或使用其它的 session 后端。此外,数据库套接字需要被放入 jail 或者侦听 localhost 接口。如果使用网络函数,某些 /etc 下面的文件例如 /etc/resolv.conf 和 /etc/services 需要被移动到 /var/www/etc 中去。OpenBSD PEAR 包会自动安装到正确的 chroot 目录中,因此不需要作特殊改动。有关 OpenBSD Apache 的更多信息见 OpenBSD FAQ。
对应于 gd 扩展的 OpenBSD 3.6 包需要预先安装 XFree86。如果不想使用那些需要 X11 的字体特性,则安装 php4-gd-4.3.8-no_x11.tgz 包来替代之。
早期的 OpenBSD 系统使用 FLAVORS 系统把 PHP 连接为静态模式。自从使用这种方法编译就造成了问题:很难制作二进制软件包。仍然可以使用早期稳定的 ports trees,但这种方式已经不被 OpenBSD 小组所支持。如果对此有任何建议和意见,软件包当前的维护人是 Anil Madhavapeddy(avsm at openbsd dot org)。
本节包含了在 Solaris 系统上安装 PHP 的说明和提示。
本节包含了在 Debian GNU/Linux 下安装 PHP 的说明和提示。
当然可以下载 PHP 源代码并自己编译,不过使用 Debian 的软件包系统是安装 PHP 的最简单和最干净利落的方法。如果不熟悉在 Linux 下编译软件,那最好用此方法。
首先要决定是安装 Apache 1.3.x 还是 Apache 2.x。相对应的 PHP 软件包名字为 libapache-mod-php* 和 libapache2-mod-php*。以下步骤以 Apache 1.3.x 为例。注意迄今为止,还没有 PHP 5 的正式的 Debian 软件包。以下步骤将安装 PHP 4。
PHP 在 Debian 下也有 CGI 和 CLI 两种风格,分别命名为 php4-cgi 和 php4-cli。如果需要的话,只要用正确的软件包名称重复以下步骤。另外需要安装的一个特殊软件包是 php4-pear。它包含了最小的 PEAR 安装以及 pear 命令行工具。
如果需要比 Debian 的稳定版本更新的 PHP 包或者一些不在 Debian 官方库中的 PHP 模块,那应该看看 http://www.apt-get.org/。其中可以找到一个 Dotdeb。此非官方库是由 Guillaume Plessis 负责维护,其中包含了最新版 PHP 4 和 PHP 5 的 Debian 软件包。要使用,只需将以下两行添加到 /etc/apt/sources.lists 并运行 apt-get update:
最后要考虑的是自己的软件包列表是否是最新版。如果最近没有更新过,那需要在做任何事之前先 apt-get update。这样就可以使用最近稳定版的 Apache 和 PHP 软件包了。
所有准备做好之后,就可以按照下面的例子来安装 Apache 和 PHP:
APT 将自动安装 Apache 1.3 的 PHP 4 模块以及所有依赖的库并激活之。如果在安装过程中没有被要求重启动 Apache,那必须手工进行:
上一节中 PHP 仅安装了核心模块。但可能不够用,用户很快就会发现需要更多的激活模块,例如 MySQL,cURL,GD 等。
当自己从源代码编译 PHP 时,需要通过 configure 命令来激活模块。用 APT 则只需安装附加的软件包。这些包都命名为“php4-*”(或“php5-*”,如果安装了第三方的 PHP 5 的话)。
从上面的输出中可以看到,还有很多 PHP 模块可安装(除了 php4-cgi,php4-cli 或 php4-pear 这些特殊软件包)。仔细察看并安装自己所需要的。如果选择了一个模块而没有相应的库,APT 会自动安装所有依赖的库。
如果选择将 MySQL,cURL 和 GD 支持添加到 PHP 中,则其命令类似于:
APT 会自动把适当的行添加到不同的 php.ini(/etc/php4/apache/php.ini,/etc/php4/cgi/php.ini 等)中去。
只需像之前那样重新启动 Apache 来激活这些模块。
如果看到了 PHP 源代码而不是脚本应该产生的结果,则 APT 可能没有 /etc/apache/conf.d/php4 包括到 Apache 1.3 配置中去。请确保下面一行出现在 /etc/apache/httpd.conf 文件中并重启动 Apache:
如果安装了更多模块但其函数不能在脚本中使用,请确保相应的配置行出现在 php.ini 中,如上面所说。APT 可能会由于混乱的 debconf 配置而在安装附加模块时失败。
本章包括在 Mac OS X 平台下安装 PHP 的说明和提示。Mac OS X 有两个不同的版本,客户版和服务器版,本手册两者均会介绍。请注意 PHP 不能在 Mac OS 9 和更早版本下运行。
Mac OS X 下有几个预编译和打包的 PHP 版本。可以通过它使用标准的配置的 PHP,但是若需要不同的功能集(比如一个安全服务器,或者一个不同的数据库驱动程序),可能需要自己编译 PHP 和/或 web 服务器。如果不熟悉如何自己编译软件,可以试着找一下包含自己所需功能的 PHP 预编译版本。
获得最新版本的 Apache 和 PHP。
将它们的 tar 包解压,然后如下运行 Apache 的 configure 程序。
./configure --exec-prefix=/usr \ --localstatedir=/var \ --mandir=/usr/share/man \ --libexecdir=/System/Library/Apache/Modules \ --iconsdir=/System/Library/Apache/Icons \ --includedir=/System/Library/Frameworks/Apache.framework/Versions/1.3/Headers \ --enable-shared=max \ --enable-module=most \ --target=apache |
如果想对编译做些优化,可以添加下面一行:
setenv OPTIM=-O2 |
接下来,进入 PHP 4 源代码目录,并进行 configure 操作。
./configure --prefix=/usr \
--sysconfdir=/etc \
--localstatedir=/var \
--mandir=/usr/share/man \
--with-xml \
--with-apache=/src/apache_1.3.12 |
--with-apache 参数,需要将其路径指向
Apache 源代码目录,例如
/src/apache_1.3.12。
输入 make 和 make install。这样在 Apache 源代码目录中会创建一名为 src/modules/php4 的目录。
现在,重新配置 Apache 以编译 PHP 4。
./configure --exec-prefix=/usr \ --localstatedir=/var \ --mandir=/usr/share/man \ --libexecdir=/System/Library/Apache/Modules \ --iconsdir=/System/Library/Apache/Icons \ --includedir=/System/Library/Frameworks/Apache.framework/Versions/1.3/Headers \ --enable-shared=max \ --enable-module=most \ --target=apache \ --activate-module=src/modules/php4/libphp4.a |
从 PHP 4 源代码目录复制并重命名 php.ini-dist 文件到 bin 目录:cp php.ini-dist /usr/local/bin/php.ini 或(如果没有 local 目录)cp php.ini-dist /usr/bin/php.ini。
以下说明将会帮助在 Mac OS X 下为 Apache 服务器安装 PHP 模块,并添加 MySQL 和 PostgreSQL 的支持。本说明是由 Marc Liyanage 提供的。
| 警告 |
请注意,在按照下面的步骤操作时,应该停止 Apache 服务器! |
按照下面的步骤安装:
打开终端窗口。
输入 wget http://www.diax.ch/users/liyanage/software/macosx/libphp4.so.gz,等待下载完毕。
输入 gunzip libphp4.so.gz。
输入 sudo apxs -i -a -n php4 libphp4.so。
现在输入 sudo open -a TextEdit /etc/httpd/httpd.conf。TextEdit 将把 web 服务器的配置文件打开。在文件的末尾找到下面两行(使用查找命令):
#AddType application/x-httpd-php .php #AddType application/x-httpd-php-source .phps |
最后,输入 sudo apachectl graceful 重新启动 web 服务器。
PHP 现在应该已经配置好,并且正在运行了。可以在 Sites 文件夹创建一名为 test.php 的文件。该文件的内容为: <?php phpinfo() ?>。
现在在 web 浏览器浏览 127.0.0.1/~your_username/test.php。应该可以看到一个表格列出了 PHP 模块的信息。
本节内容适用于 Windows 98/Me 以及 Windows NT/2000/XP/2003。PHP 不能在 16 位平台例如 Windows 3.1 下运行。有时把支持 PHP 的 Windows 平台称为 Win32。自 PHP 4.3.0 开始不再支持 Windows 95。
有两种方法在 Windows 下安装 PHP:手工安装或者使用安装程序安装。
如果有 Microsoft Visual Studio,也可以编译 PHP 的源程序。
一旦在 Windows 系统下安装好 PHP 之后,可能需要加载各种扩展库以实现更多的功能。
| 警告 |
互联网上还有一些多合一的安装程序,但是它们没有一个是被 PHP.net 认可的,因为我们相信,手动安装是系统安全和优化的最好选择。 |
PHP 的 Windows 安装程序可以在 http://www.php.net/downloads.php 下载。它会为 IIS、PWS 和 Xitami 安装 CGI 版本的 PHP,并配置好 web 服务器。该安装程序不包含任何外部的 PHP 扩展(PHP_*.dll)。如果需要,可以在 Windows ZIP 包和 PECL 中找到。
注意: 虽然 Windows 安装程序是让 PHP 工作的最容易的方法,但是它有很多限制。例如,它不支持自动安装 PHP 扩展。使用安装程序安装 PHP 不是最好的方式。
首先,在系统中安装自己选择的 HTTP(web)服务器,并确认它正常工作。
运行安装程序,按照向导说明一步步安装。它支持两种安装类型:标准,将使用合理的默认配置进行安装;高级,会在配置中询问几个问题。
安装向导会收集足够的信息来设置 php.ini 文件,并配置好 web 浏览器以使用 PHP。PHP 安装程序不能自动配置 Apache,因此需要手动进行配置。
一旦安装完成,安装程序会提示重新启动系统,重启服务器,或直接开始使用 PHP。
| 警告 |
请注意,这种安装方式安装的 PHP 不是安全的。如果需要一个安全的 PHP 设置,最好使用手动方式安装,并手动设置好每个选项。该自动安装程序能够让用户立即使用 PHP,但是这不意味着可以用于在线的服务器中。 |
本安装指南指导手动在一个 Microsoft Windows 的 web 服务器下安装和配置 PHP。安装前需要从 http://www.php.net/downloads.php 下载 PHP 的 ZIP 二进制发布包。
虽然目前有很多多合一的安装包,而且也发布了一个 Microsoft Windows 的 PHP 安装程序,但是仍然建议用户花些时间自己手动安装 PHP。因为这样才可以更加了解这套系统,并能够在需要的时候更方便的安装 PHP 扩展。
从旧版本的 PHP 升级: 上一版的手册建议将 ini 和多个 DLL 文件移动到系统文件夹(例如 C:\WINDOWS)。这一步骤虽然简化了安装过程,却导致升级上的困难。建议在使用新版本的 PHP 前删除所有这些文件(比如从 Windows 系统文件夹删除 php.ini 和 PHP 相关的 DLL 文件)。务必在删除前备份这些文件,因为这一操作可能破坏整个系统。原有的 php.ini 在安装新版本的 PHP 时也可用来参考。不久用户便会明白,安装 PHP 最好的方式便是将所有 PHP 有关的文件都放入同一目录,并在系统的 PATH 环境变量中设置此目录。
MDAC 需求: 如果使用 Microsoft Windows 98/NT4,需要下载适用于系统最新版本的 Microsoft Data Access Components(MDAC)。MDAC 可在 http://msdn.microsoft.com/data/ 下载。需要 MDAC 的原因是 Windows 二进制包中编译进了 ODBC 支持。
不论何种 web 服务器,都需要先进行以下步骤:
将 PHP 压缩包释放到选择的目录中。若使用 PHP 4,可以解压缩到 C:\,压缩包会被释放到一个类似 php-4.3.7-Win32 的新目录中。若使用 PHP 5,请解压缩到 C:\php,因为其 ZIP 包内没有类似 php-4.3.7-Win32 的目录信息。可以选择其它的路径但最好不要用中间有空格的路径(例如:C:\Program Files\PHP 就不太好),如果这样做有些 web 服务器会崩溃。
解压缩后的目录对应 PHP 4 和 5 是不同的。它们的目录结构分别为:
例 6-1. PHP 4 目录结构
|
或:
例 6-2. PHP 5 目录结构
|
请注意它们之间的不同和相似之处。PHP 4 和 PHP 5 都有一个 CGI 可执行文件、一个 CLI 可执行文件和服务器模块,但是它们位于不同的文件夹和/或有着不同的命名。PHP 4 将服务器模块放在 sapi 文件夹,而 PHP 5 并没有此目录,它的服务器模块文件位于 PHP 根文件夹中。PHP 5 的扩展支持 DLL 文件也并没有放在一个单独的目录中。
注意: 在 PHP 4 中,需要将位于 dll 和 sapi 文件夹中的文件移动到主文件夹中(例如 C:\php)。
下面是 PHP 4 和 PHP 5 附带的服务器模块列表:
sapi/php4activescript.dll (php5activescript.dll) - ActiveScript 引擎,允许将 PHP 嵌入 Windows 应用程序中。
sapi/php4apache.dll(php5apache.dll) - Apache 1.3.x 模块。
sapi/php4apache2.dll(php5apache2.dll) - Apache 2.0.x 模块。
sapi/php4isapi.dll(php5isapi.dll) - ISAPI 模块,支持 ISAPI 兼容的 web 服务器,比如 IIS 4.0/PWS 4.0 或更新版本。
sapi/php4nsapi.dll(php5nsapi.dll) - Sun/iPlanet/Netscape 服务器模块。
sapi/php4pi3web.dll(PHP 5 无此模块) - Pi3Web 服务器模块。
服务器模块比 CGI 可执行程序提供了更好的性能和更多的功能。CLI 版本是为使用 PHP 命令行脚本而设计的。关于 CLI 的更多信息可以在 PHP 的命令行模式一章中找到。
| 警告 |
SAPI 模块在 4.1 中有较多的增强。但是,在老系统中可能会产生服务器错误,或导致服务器的其它模块停止工作,比如 ASP。 |
CGI 和 CLI 可执行文件以及 web 服务器模块都需要 php4ts.dll(php5ts.dll)。必须确认该文件可以在 PHP 安装路径中找到。对该 DLL 的搜索顺序为:
调用 php.exe 时所在的目录,或者若使用 SAPI 模块时,web 服务器的目录(例如 C:\Program Files\Apache Group\Apache2\bin)。
任何在 Windows 的 PATH 环境变量中指定的目录。
要让 php4ts.dll / php5ts.dll
能正确被搜索到,有下面三个选择:复制该文件到 Windows 系统目录,复制该文件到 web
服务器的目录,或者把 PHP 目录(例如 C:\php)添加到 PATH
环境变量中。为了将来更好的维护,建议使用最后一个选择,将 PHP 目录添加到
PATH 环境变量中,因为这样更便于将来升级 PHP。在相应的常见问题解答项目中可以了解如何将
PHP 目录添加到
PATH 环境变量中(别忘了重新启动电脑,光注销还不够)。
下一步是为 PHP 设置一个有效的配置文件,php.ini。在 ZIP 包中有两个 ini 文件,php.ini-dist 和 php.ini-recommended。建议使用 php.ini-recommended,因为在该文件中优化了性能和安全。请仔细阅读该文件中的注释,因为它从 php.ini-dist 修改而来,会对设置产生较大的影响。例如将 display_errors 设置为 off,将 magic_quotes_gpc 设置为 off。除了阅读这些部分,还可以学习一下 ini 设置,并手动设置每一个配置项目。如果想要最安全的设置,这是最好的方法,虽然 PHP 在默认配置下也是很安全的。复制所选择的 ini 文件到 PHP 能找到的目录中,并将其重命名为 php.ini。PHP 搜索 php.ini 的路径在配置文件一节已有介绍。
如果使用 Apache 2,更简单的选择是使用 PHPIniDir
指令(请阅读在 Apache 2
下的安装);若不是,最好的选择是设置
PHPRC 环境变量。它在此常见问题解答项目中进行了解释。
注意: 如果在 Windows NT、2000、XP 或 2003 中使用 NTFS 分区,请确认运行 web 服务器的用户有权限读取 php.ini(例如将其设置为 Everyone 可读)
下面的步骤是可选的:
编辑新的 php.ini 文件。如果计划使用 OmniHTTPd,不要执行下一步。设置 doc_root 并指向 web 服务器的 document_root。例如:
选择 PHP 装载的扩展库。请阅读关于 Windows 扩展一节以了解如何设置扩展库,以及哪些功能已经内置无需扩展库。请注意建议在全新安装时先不要在 php.ini 中加载任何扩展库,首先要保证 PHP 自身能够正常工作。
在 PWS 和 IIS,可以设置 browscap 配置:在 Windows 9x/Me 中指向 c:\windows\system\inetsrv\browscap.ini,在 NT/2000 中指向 c:\winnt\system32\inetsrv\browscap.ini,在 XP 中指向 c:\windows\system32\inetsrv\browscap.ini。要得到最新版本的 browscap.ini,请阅读如下常见问题解答项目。
PHP 现在已经安装在系统中了。接下来一步是选择一个 web 服务器,并为之启用 PHP。请在本章目录中选择一个 web 服务器以了解更详细的安装步骤。
本节将介绍有关 ActiveScript 安装需要注意的方面。
ActiveScript 是一个只运行在 Windows 下的 SAPI,可以在任何兼容 ActiveScript 的主机上使用 PHP 脚本,例如 Windows Script Host、ASP/ASP.NET、Windows Script Components 或 Microsoft Scriptlet control。
PHP 5.0.1 以后,ActiveScript 被移动到了PECL 库。可以从 PHP 下载页面或者 http://snaps.php.net/ 下载此 PECL 扩展的 DLL 文件。
注意: 应该首先阅读手动安装步骤!
PHP 安装完成后,应该下载 ActiveScript DLL(php5activescript.dll)并将其放入 PHP 主目录(例如 C:\php)。
准备好全部所需文件后,必须在系统中注册 DLL。做法是打开命令提示行窗口(位于开始菜单),然后输入类似 cd C:\php 的命令进入 PHP 目录,最后输入 regsvr32 php5activescript.dll 注册该 DLL。
要测试 ActiveScript 是否正确工作,请创建一个新文件,命名为 test.wsf(这个扩展名很重要)然后输入:
<job id="test">
<script language="PHPScript">
$WScript->Echo("Hello World!");
</script>
</job> |
注意: 在 PHP 4 中,该引擎被命名为“ActivePHP”,如果使用 PHP 4,应该将上例中的“PHPScript”替换为“ActivePHP”。
注意: ActiveScript 不使用默认的 php.ini 文件,而仅在调用它的 .exe 文件所在目录中寻找。如果想装载 PHP 扩展等,应该创建 php-activescript.ini 并将其放入那个目录。
本节包括针对 IIS(Microsoft Internet Information Server)的说明与提示。
| 警告 |
如果使用 CGI 方式安装,则服务器对于某些可能的攻击是开放的。请阅读 CGI 安全一章以学习如何防御这些攻击。 |
首先请阅读手工安装步骤。不要跳过这一步,这里提供了将 PHP 安装到 Windows 中的极其重要的信息。
CGI 用户必须在 php.ini 中将 cgi.force_redirect 指令设为 0。其重要细节请阅读 FAQ 中的cgi.force_redirect。此外,CGI 用户可能需要设定 cgi.redirect_status_env 指令。在使用这些指令时,确保它们没有在 php.ini 中被注释掉。
PHP 4 的 CGI 文件名是 php.exe 而在 PHP 5 中是 php-cgi.exe。在 PHP 5 中,php.exe 是 CLI 版本,不是 CGI。
修改 Windows 的 PATH 环境变量以把 PHP 目录包括进去。这样 PHP 的 DLL 文件,可执行文件和 php.ini 就都可以保留在 PHP 目录中而不用把 Windows 系统目录搞乱了。更多细节见 FAQ 中的设定路径 PATH。
IIS 专用用户(通常为 IUSR_MACHINENAME)需要能够读取各个文件和目录的权限,例如 php.ini,docroot 和 session 的 tmp 目录。
确保在 php.ini 中正确设定了 extension_dir 和 doc_root 指令的值。这些指令依赖于 PHP 被安装的系统。在 PHP 4 中,extension_dir 是 extensions 而在 PHP 5 中是 ext。因此在 PHP 5 中 extensions_dir 的一个取值例子是 "c:\php\ext",IIS 的 doc_root 的取值例子是 "c:\Inetpub\wwwroot"。
PHP 扩展库的 DLL 文件,如 php_mysql.dll 和 php_curl.dll,存放于 PHP 下载的 ZIP 包中(自动安装包里没有)。在 PHP 5 中,很多扩展库都是 PECL 的一部分,可以从“Collection of PECL modules”包中下载,例如 php_zip.dll 和 php_ssh2.dll。点击进入 PHP 下载页。
在定义应用程序扩展名映射时,应选中“检查文件是否存在”。以极小的性能为代价,IIS(或者 PWS)会在调用 PHP 之前检查脚本文件是否存在并选出认证方法。这意味着 web 服务器会提供一个有道理的 404 形式错误信息而不是一条 CGI 错误说什么 PHP 没有输出任何数据。
PHP 可以安装为 CGI 或者 ISAPI 模块。不管哪种,都需要启动 Microsoft 管理控制台(也可能是“Internet 信息服务”,在 Windows NT 4.0 Option Pack 中或者在 Windows 2000/XP 下的控制面板=>管理工具)。然后右键点击 web 服务器节点(通常为“默认网站”),并选择“属性”。
如果想用 CGI 方式,按如下方法进行:
选择“主目录”,“虚拟目录”或“目录”标签页,然后进行:
将执行权限改为“纯脚本”
点“配置”按钮,选择“映射”标签页。点击“添加”按钮,将“可执行文件”指向适当的 CGI 文件名。例如 PHP 5 的值可能是:C:\php\php-cgi.exe。在“扩展名”中填入 .php。选择“全部动作”(或者“限制为”留空),选中“脚本引擎”。然后点击“确定”。
设定合适的目录安全性(在 Internet 信息服务中完成)。如果 NT 服务器使用 NTFS 文件系统,给 I_USR_ 用户加上 php.exe/php-cgi.exe 文件所在目录的可执行权限(通过资源管理器完成)。
要用 ISAPI 模块方式,按如下方法进行:
如果不想用 PHP 进行 HTTP 认证,应该跳过这一步。在“ISAPI 筛选器”标签页中添加一个新的 ISAPI 筛选器。“筛选器名称”设为 PHP,“可执行文件”设为 php4isapi.dll/php5isapi.dll 的路径。
选择“主目录”,“虚拟目录”或“目录”标签页,然后进行:
将执行权限改为“纯脚本”
点“配置”按钮,选择“映射”标签页。点击“添加”按钮,将“可执行文件”指向适当的 ISAPI DLL。例如 PHP 5 的值可能是:C:\php\php5isapi.dll。在“扩展名”中填入 .php。选择“全部动作”(或者“限制为”留空),选中“脚本引擎”。然后点击“确定”。
完全停止 IIS(NET STOP iisadmin)
重新启动 IIS(NET START w3svc)
对于 IIS 6(2003 Server),打开 IIS 管理器,进入 web 服务扩展,点击“添加一个新的 web 服务扩展”,“扩展名”中输入名称,例如 PHP,再点击“添加”按钮,点击“浏览”选择要么 ISAPI 文件(php4isapi.dll 或 php5isapi.dll)或者 CGI 文件(php.exe 或 php-cgi.exe)作为“文件路径”后点“确定”,然后选中“设置扩展状态为允许”并点“确定”。
要使用 index.php 作为默认文档,在“文档”标签页中选择“添加”。输入 index.php 并点“确定”。用上下箭头按钮调整顺序。这和在 Apache 中设定 DirectoryIndex 相似。
对于每个要关联为 PHP 脚本的后缀都要重复以上步骤。.php 是最常用的,此外为兼容一些遗留下来的老程序可能还需要加上 .php3。
如果过些时候之后碰到 CPU 占用率达到 100%,则取消选中“缓存 ISAPI 应用程序”(“主目录”下点“配置”按钮”)。
PWS 4 不支持 ISAPI,只能使用 PHP CGI。
编辑包里附上的 pws-php4cgi.reg/pws-php5cgi.reg 文件(PHP 4 在 SAPI 目录下,PHP 5 在主目录下)改为自己的 php.exe/php-cgi.exe 文件的路径。反斜线应双写,例如:[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\w3svc\parameters\Script Map] ".php"="C:\\php\\php.exe"(如果用 PHP 5 则改为 C:\\php\\php-cgi.exe)。然后将此注册表文件合并入系统;鼠标双击此文件即可。
在 PWS 管理器中,右键点击需要加入 PHP 支持的目录并选择“属性”。选中“执行”,并确认。
配置此服务器的推荐方法是使用随包发布的注册表文件(PHP 4 是 SAPI 目录下的 pws-php4cgi.reg,PHP 5 是主目录下的 pws-php5cgi.reg)。可能要编辑此文件已确保其中的 PHP 安装目录和扩展库目录符合用户自己的设置。或者按以下步骤手工完成。
| 警告 |
以下步骤涉及到直接操作 Windows 注册表。如果出错可能使系统不稳定,强烈建议先备份注册表。如果用户损坏了注册表 PHP 开发组不负任何责任。 |
运行 Regedit。
找到:HKEY_LOCAL_MACHINE /System /CurrentControlSet /Services /W3Svc /Parameters /ScriptMap。
在编辑菜单选择:新建->字符串值。
输入 PHP 脚本想要使用的后缀,例如 .php。
双击新建的字符串值并在“数值数据”栏里输入 php.exe 的路径,例如 PHP 4 是 C:\php\php.exe "%s" %s,或者 PHP 5 是 C:\php\php-cgi.exe "%s" %s。
对每个要关联为 PHP 脚本的文件后缀名重复以上步骤。
以下步骤不影响 web 服务器安装,仅适用于想在命令行下运行 PHP 脚本(例如运行 C:\myscripts\test.php)或者在资源管理器窗口中双击文件名就运行程序。如果更希望双击 PHP 文件名是将其调入文本编辑器,则跳过以下步骤。
找到:HKEY_CLASSES_ROOT。
在编辑菜单选择:新建->项。
将新项命名为前一节设的后缀,例如:.php。
选中新项,在右边栏双击“默认”并输入 phpfile。
对每个在前一节设定的后缀都重复以上步骤。
在 HKEY_CLASSES_ROOT 下再创建另一个新建->项 并命名为 phpfile。
选中新项 phpfile,在右边栏双击“默认”并输入 PHP Script。
右键点击 phpfile 项并选择新建->项,命名为 Shell。
右键点击 Shell 项并选择新建->项,命名为 open。
右键点击 open 项并选择新建->项,命名为 command。
选中新项 command,在右边栏双击“默认”并输入 php.exe 的路径,例如:c:\php\php.exe -q %1(不要忘了 %1)。
退出 Regedit。
如果是 Windows 下的 PWS,重启动以重新加载注册表。
PWS 和 IIS 3 的用户现在就拥有了完全可运作的系统。IIS 3 用户可以使用来自 Steven Genusa 的漂亮工具来配置脚本映射。
本节包括在 Microsoft Windows 平台的 Apache 下安装 PHP 的说明和提示。在另外的页面也有 Apache 2 的安装和说明。
注意: 应该首先阅读手动安装步骤!
有两种方式让 PHP 工作在 Windows 下的 Apache 1.3.x 中。首先是使用 CGI 可执行程序(PHP 4 下为 php.exe,PHP 5 下为 php-cgi.exe),另外一种方式是使用 Apache 模块 DLL。无论是那种方式,都需要修改 httpd.conf 来配置 Apache,使 PHP 能够在其上运行,然后都需要重启服务。
值得注意的是,现在 Windows 下的 SAPI 模块已经稳定得多,我们建议首先考虑使用 SAPI 而不要使用 CGI 可执行程序。因为 SAPI 更加透明和安全。
虽然还有些其它的方法来在 Apache 下配置 PHP,下面介绍的方法是最简单并适用于新手的。请参考 Apache 的文档以获得更多的配置参数。
在修改完配置文件后,请记得重启 Apache 服务。例如,如果把 Apache 作为 Windows 的一个服务来运行,那么在命令提示行下使用 NET STOP APACHE 命令然后再使用 NET START APACHE 命令便可重启服务。也可以使用重启 Apache 服务的快捷方式来重启。
注意: 记住在 Windows 下给 Apache 的配置文件中加入路径值的时候,所有的反斜线例如 c:\directory\file.ext 必须转换成正斜线,如 c:/directory/file.ext。
应该将下面几行加入 Apache 的 httpd.conf 文件:
例 6-3. PHP 作为 Apache 1.3.x 的一个模块 这里假设 PHP 安装在 c:\php。如果不是这样请根据情况修改路径。 对于 PHP 4:
对于 PHP 5:
两个 PHP 版本都需要添加的内容:
|
如果按照手动安装步骤将 PHP 解压到 C:\php\,需要在 Apache 的配置文件中添加如下内容以使 PHP 按照 CGI 方式运行:
| 警告 |
如果使用 CGI 方式安装,则服务器对于某些可能的攻击是开放的。请阅读 CGI 安全一章以学习如何防御这些攻击。 |
如果想发布语法高亮的 php 文件,没有类似于模块方式下 PHP 那种方便的方法。选择了使用 CGI 方式运行 PHP,需要使用 highlight_file() 函数来进行语法高亮。创建一个 PHP 文件,加入下述代码即可:<?php highlight_file('some_php_script.php'); ?>。
本节包括在 Microsoft Windows 系统中针对 Apache 2.0.x 安装 PHP 的指导与说明。在其它页面也有 Apache 1.3.x 用户指导与说明。
注意: 应该先阅读手工安装步骤!
| 警告 |
不推荐将线程化 MPM 用于实际运作的 Apache 2 环境中去。用 prefork MPM 替代,或者用 Apache 1。其原因见 FAQ 中的使用线程化 MPM 的 Apache2。 |
强烈建议阅读 Apache 文档来加深对 Apache 2.0.x 服务器的基本理解。此外在继续下去之前考虑先阅读一下 Apache 2.0.x 的 Windows 下使用说明。
PHP 和 Apache 2.0.x 兼容性注意事项: 已知下列版本的 PHP 可以工作于最近版本的 Apache 2.0.x 之下:
以上版本的 PHP 与 Apache 2.0.40 或更高版本兼容。
- PHP 4.3.0 或更高版本,可从 http://www.php.net/downloads.php 下载。
- 最新的稳定开发版。取得源代码 http://snaps.php.net/php5-latest.tar.gz 或下载 Windows 可执行程序 http://snaps.php.net/win32/php5-win32-latest.zip。
- 预发布版,可从 http://qa.php.net/ 下载。
- 总是可以通过匿名 CVS 取得 PHP。
Apache 2.0 SAPI 支持自 PHP 4.2.0 起。PHP 4.2.3 可工作于 2.0.39,不要用任何其它版本的 Apache 与 PHP 4.2.3 配合。不过推荐的设置是用 PHP 4.3.0 或更高版本与最新版的 Apache2 配合使用。
所有提及的 PHP 版本仍然能工作于 Apache 1.3.x 之下。
| 警告 |
Apache 2.0.x 被设计运行于 Windows NT 4.0,Windows 2000 或 Windows XP 之下。目前为止对 Windows 9x 的支持尚未完成,此时尚不指望 Apache 2.0.x 在此类平台下工作。 |
下载最新版本的 Apache 2.0.x 以及适合的 PHP 版本。先完成手工安装步骤后再回来继续将 PHP 集成入 Apache。
Windows 下有两种方法使 PHP 工作于 Apache 2.0.x 之中。一种是 使用 CGI 可执行程序,另一种是适用 Apache 模块的 DLL。不管哪种都需要编辑 httpd.conf 来配置 Apache 支持 PHP 并重新启动服务器。
注意: 记住在 Windows 下给 Apache 的配置文件中加入路径值的时候,所有的反斜线例如 c:\directory\file.ext 必须转换成正斜线,如 c:/directory/file.ext。
需要将以下三行加入到 Apache 的 httpd.conf 配置文件中以设定 CGI:
| 警告 |
如果使用 CGI 方式安装,则服务器对于某些可能的攻击是开放的。请阅读 CGI 安全一章以学习如何防御这些攻击。 |
需要将以下两行加入到 Apache 的 httpd.conf 配置文件中以设定 Apache 2.0 的 PHP 模块:
例 6-6. PHP 在 Apache 2.0 中的模块方式
|
注意: 记得用自己 PHP 实际所在的路径替换掉上例中的 c:/php/。要留意在 LoadModule 指令中用的是 php4apache2.dll 或 php5apache2.dll,而不是 php4apache.dll 或 php5apache.dll,后者是设计用于 Apache 1.3.x 的。
注意: 如果要使用内容协商机制,请阅读有关 FAQ。
| 警告 |
不要在安装中混合使用来自不同 PHP 版本的 DLL。使用下载回来的 PHP 版本中所提供的 DLL 和扩展库是唯一选择。 |
本节包含针对在 Windows 下 Sun Java System web 服务器,Sun ONE web 服务器,iPlanet 和 Netscape 服务器的 PHP 安装说明与提示。
自 PHP 4.3.3 起可以通过 NSAPI 模块使用 PHP 脚本来产生定制目录列表于错误页面。也可以使用为兼容 Apache 的附加函数。目前使用的 web 服务器的支持请阅读有关子请求的说明。
要将 PHP 安装为 CGI 处理器,按以下步骤进行:
将 php4ts.dll 拷贝到 systemroot(即 Windows 的安装目录)
在命令行做文件关联,输入以下两行命令:
assoc .php=PHPScript ftype PHPScript=c:\php\php.exe %1 %* |
在 Netscape Enterprise Administration Server 中建一个空的 shellcgi 目录并随即删除(此步骤在 obj.conf 中新建了 5 行重要指令以允许 web 服务器处理 shellcgi 脚本)。
在 Netscape Enterprise Administration Server 中新建一个新的 MIME 类型(Category: type,Content-Type: magnus-internal/shellcgi,File Suffix: php)。
对每个要运行 PHP 的 web 服务器实例都进行以上步骤。
更多将 PHP 设置为 CGI 可执行程序的内容见:http://benoit.noss.free.fr/php/install-php.html。
要将 PHP 以 NSAPI 方式安装,按以下步骤进行:
将 php4ts.dll 拷贝到 systemroot(即 Windows 的安装目录)
在命令行做文件关联,输入以下两行命令:
assoc .php=PHPScript ftype PHPScript=c:\php\php.exe %1 %* |
在 Netscape Enterprise Administration Server 中新建一个新的 MIME 类型(Category: type,Content-Type: magnus-internal/x-httpd-php,File Suffix: php)。
编辑 magnus.conf(服务器版本 >= 6)或 obj.conf(服务器版本 < 6)并加入下面两行;要将新行放在 mime types init 之后:
Init fn="load-modules" funcs="php4_init,php4_execute,php4_auth_trans" shlib="c:/php/sapi/php4nsapi.dll" Init fn="php4_init" LateInit="yes" errorString="Failed to initialise PHP!" [php_ini="c:/path/to/php.ini"] |
在 obj.conf 中配置默认对象(对于虚拟服务器类 [Sun web Server 6.0+] 是 vserver.obj.conf 文件):在 <Object name="default"> 一节,在所有的“ObjectType”行之后和所有的“AddLog”行之前加上这一行:
Service fn="php4_execute" type="magnus-internal/x-httpd-php" [inikey=value inikey=value ...] |
这几行仅在想要配置一个只有 PHP 脚本的目录时需要(类似 cgi-bin 目录):
<Object name="x-httpd-php"> ObjectType fn="force-type" type="magnus-internal/x-httpd-php" Service fn=php4_execute [inikey=value inikey=value ...] </Object> |
重启动 web 服务使改动生效。
对每个要运行 PHP 的 web 服务器实例都进行以上步骤。
注意: 更多将 PHP 设置为 NSAPI内容见:http://benoit.noss.free.fr/php/install-php4.html。
注意: PHP 使用的堆栈大小(stacksize)依赖于 web 服务器的配置。如果在运行很大的 PHP 脚本时死掉,建议在管理服务器中增大此值(在 "MAGNUS EDITOR" 一节中)。
在写 PHP 脚本时很重要一点是 Sun JSWS/Sun ONE WS/iPlanet/Netscape 是多线程 web 服务器。因此所有的请求都运行于同一个进程空间(即 web 服务器自己的空间)而此空间只有一个环境。如果想取得 CGI 变量例如 PATH_INFO,HTTP_HOST 等时不能用老的 PHP 3.x 的方式 getenv() 或者类似手段($_ENV)进行。只能取得运行的 web 服务器的环境变量而没有任何有效的 CGI 变量!
注意: 为什么环境中有一些(无效的)CGI 变量?
解答:这是因为从管理服务器启动了 web 服务器进程,这将运行 web 服务器的启动脚本,而你想要启动的是 CGI 脚本(CGI 脚本在管理服务器内部!)。这是为什么 web 服务器启动的环境中有一些 CGI 环境变量的原因。可以不从管理服务器启动 web 服务器来试验一下。用管理员用户从命令行手工启动――这样就不会看到类似 CGI 的环境变量了。
PHP 4.x 中取得 CGI 变量的正确方式是使用超全局变量 $_SERVER。如果有一些老的脚本用了 $HTTP_HOST 等,那应该在 php.ini 中打开 register_globals 选项并改变变量顺序(重要提示:去掉 "E",因为这里不需要环境变量):
variables_order = "GPCS" register_globals = On |
可以用 PHP 来为 "404 Not Found" 或类似的错误提示生成错误页面。对每个想要覆盖的错误页面在 obj.conf 中的对象里加入下面这行:
Error fn="php4_execute" code=XXX script="/path/to/script.php" [inikey=value inikey=value...] |
还可以生成自己定制的目录列表。只要创建一个显示目录列表的 PHP 脚本并用下面一行在 obj.conf 中替换掉相应 type="magnus-internal/directory" 默认的 Service 设置:
Service fn="php4_execute" type="magnus-internal/directory" script="/path/to/script.php" [inikey=value inikey=value...] |
NSAPI 模块现在支持 nsapi_virtual() 函数(别名:virtual())来进行子请求并将结果插入到 web 页面里。问题是,此函数用到了一些 NSAPI 库中没有文档说明的特性。
在 Unix 下这不是问题,因为模块会自动寻找所需的函数并使用。如果找不到,nsapi_virtual() 被禁用。
在 Windows 下 DLL 处理的局限性需要使用最新的 ns-httpdXX.dll 文件中的自动检测功能。这已在版本 6.1 及以下的服务器中测试过。如果用了更高版本的 Sun 服务器,检测会失败并禁用 nsapi_virtual()。
在这种情况下,试试下面的方法。在 magnus.conf/obj.conf 中的 php4_init 里加入下面的参数:
Init fn=php4_init ... server_lib="ns-httpdXX.dll" |
可以用 phpinfo() 函数来检查状态。
注意: 但要注意:对 nsapi_virtual() 的支持是试验性质的!
本节包括针对 Windows 下的 OmniHTTPd 的内容与提示。
注意: 应该首先阅读手工安装步骤!
| 警告 |
如果使用 CGI 方式安装,则服务器对于某些可能的攻击是开放的。请阅读 CGI 安全一章以学习如何防御这些攻击。 |
要在 OmniHTTPd 中安装 PHP 需要完成以下步骤。这是 CGI 方式的安装。OmniHTTPd 支持 SAPI,但是有测试显示以 ISAPI 模块方式使用 PHP 不太稳定。
CGI 用户重要提示: 请阅读 FAQ:cgi.force_redirect 中的重要细节。此选项需要被设为 0。
安装 OmniHTTPd 服务器。
右键点击系统托盘中蓝色的 OmniHTTPd 图标并选择 Properties
点击 web Server Global Settings
在“External”标签页,输入:virtual = .php | actual = c:\php\php.exe(如果是 PHP 5 则用 php-cgi.exe),并点击 Add 按钮
在 Mime 标签页,输入:virtual = wwwserver/stdcgi | actual = .php,并点击 Add 按钮
点击 OK
对每个想要和 PHP 关联的后缀都重复 2 - 6 步。
注意: 有些 OmniHTTPd 安装包中内置了 PHP 支持。可以在安装时选择自定义安装,取消选中 PHP 部分。推荐使用最新的 PHP 可执行包。有些 OmniHTTPd 服务器内置了 PHP 4 beta 版,应该选择不安装内置版而安装自己的版本。如果服务器已经安装了,则在上面的第 4 和 5 步用 Replace 按钮来设置新的准确的信息。
本节包含针对 Windows 下的 Sambar 服务器的说明和提示。
注意: 应该首先阅读手工安装步骤!
下面列出了怎样在 Windows 下设置 Sambar 服务器的 ISAPI 模块。
在 Sambar 安装目录中找到 mappings.ini 文件(在 config 目录中)。
打开 mappings.ini 并在 [ISAPI] 部分加入下面一行:
重启动 Sambar 服务器以使改动生效。
本节包含针对 Windows 下的 Xitami 的说明与提示。
注意: 应该首先阅读手工安装步骤!
下面列出了怎样在 Windows 下在 Xitami 中设置 PHP 的 CGI 方式。
CGI 用户重要提示: 请阅读 FAQ:cgi.force_redirect 中的重要细节。此选项需要被设为 0。如果想要使用 $_SERVER['PHP_SELF'],还必须激活 cgi.fix_pathinfo 选项。
| 警告 |
如果使用 CGI 方式安装,则服务器对于某些可能的攻击是开放的。请阅读 CGI 安全一章以学习如何防御这些攻击。 |
确保 web 服务器在运行,在浏览器中打开 Xitami 的管理控制台(通常是 http://127.0.0.1/admin),并点击 Configuration。
找到 Filters,在 File extensions(.xxx)字段中加入想要 PHP 解析的后缀名(例如 .php)。
在 Filter command 或 script 中输入 PHP 的 CGI 可执行文件名,例如 PHP 4 是 C:\php\php.exe,PHP 5 是 C:\php\php-cgi.exe。
点击“Save”图标。
重启动服务器以使改动生效。
本章讲述了在 Windows 下如何使用 Microsoft 的工具编译 PHP。要在 CygWin 中编译 PHP,请参考 Unix 系统下的安装一章。
要编译 PHP 需要 Microsoft 开发环境。推荐使用 Microsoft Visuaul C++ 6.0,不过 Visual C++ .NET 版也可以用。自 PHP 5 起也支持免费的 Microsoft .NET toolchain(需要安装 Windows Platform SDK,Visual C++ Toolkit 和 .NET Framework SDK)。
要释放下载的文件还需要一个 ZIP 文件的解压缩工具。Windows XP 和更新的版本中已经内置了此功能。
在开始之前,需要先下载:
PHP 站点中的 win32 编译工具 http://www.php.net/extra/win32build.zip。
PHP 使用的 DNS 解析器的源代码:http://www.php.net/extra/bindlib_w32.zip。用这个替代 win32build.zip 中的 resolv.lib。
如果计划把 PHP 编译成 Apache 的静态模块那还需要 Apache 源程序。
最后,还需要 PHP 本身的源代码。可以通过匿名 CVS 得到最新的开发版本,一个快照或者最新发行版本的源程序的打包文件。
下载了所有的包后需要将它们解压缩到适当的位置:
建立一个工作目录作为解压缩后存放所有文件的地方,例如:C:\work。
在工作目录(C:\work)下新建一个目录 win32build 并将 win32build.zip 解压缩到其中。
在工作目录(C:\work)下新建一个目录 bindlib_w32 并将 bindlib_w32.zip 解压缩到其中。
将下载的 PHP 源程序解压缩到工作目录(C:\work)中。
要编译库还需要(或下载现成的)头文件和库文件并分别放置到 C:\work\win32build\include 和 C:\work\win32build\lib 目录中去。
如果没有安装有 bison 和 flex 的 Cygwin,那还需要将 C:\work\win32build\bin 目录放入系统 PATH 中,以使此工具可以被配置脚本找到。
+--C:\work | | | +--bindlib_w32 | | | | | +--arpa | | | | | +--conf | | | | | +--... | | | +--php-5.x.x | | | | | +--build | | | | | +--... | | | | | +--win32 | | | | | +--... | | | +--win32build | | | | | +--bin | | | | | +--include | | | | | +--lib |
如果不是用 Cygwin 的话,还必须新建一个目录 c:\usr\local\lib 并将 bison.simple 从 c:\work\win32build\bin 拷贝到 c:\usr\local\lib 中。
注意: 如果想使用 PEAR 以及舒适的命令行安装程序,就非要用 CLI-SAPI。有关 PEAR 和安装程序的更多信息见 PEAR 网站。
必须编译 resolv.lib 库。自己决定是需要调试信息(bindlib - Win32 Debug)还是不需要(bindlib - Win32 Release),但是要记住自己的选择,因为用 Debug 模式编译的 resolv.lib 只能和 Debug 模式编译的 PHP 连接。编译适当的配置:
图形界面用户,通过鼠标双击 C:\work\bindlib_w32\bindlib.dsw 运行 VC++。接着选择 Build => Rebuild All。
命令行用户,确认要么注册了 C++ 环境变量,要么运行了 vcvars.bat,然后运行下面任意一行命令:
msdev bindlib.dsp /MAKE "bindlib - Win32 Debug"
msdev bindlib.dsp /MAKE "bindlib - Win32 Release"
本节讲解了怎样用新编译系统编译 PHP >=5,此系统是基于 CLI 的,并且非常类似于 PHP 的 Unix 编译系统。
注意: 此编译系统在 PHP 4 中不可用。请参考用 DSW 文件编译 PHP一节。
开始之前要确保阅读了放到一起一节并且已经编译了所有所需的库,例如 Libxml 或 ICU(PHP >= 6 中需要)。
首先应该打开一个用于 Visual Studio 的命令行提示符,应在开始菜单中能找到。正常的命令提示符可能不能用,因为没有设定所需的环境变量。输入类似 cd C:\work\php-5.x.x 的命令进入 PHP 源程序目录。现在可以开始配置 PHP 了。
第二步是运行 buildconf 批处理文件来扫描文件夹寻找 config.w32 来建立配置脚本。默认时此命令还会搜索以下目录:pecl; ..\pecl; pecl\rpc; ..\pecl\rpc。自 PHP 5.1.0 起,可以通过 --add-modules-dir 参数来改变此行为(例如 cscript /nologo win32/build/buildconf.js --add-modules-dir=../php-gtk2 --add-modules-dir=../pecl)。
第三步是配置。要查看可用的配置选项列表,输入 cscript /nologo configure.js --help 命令。选择了需要激活或禁止的选项之后,输入类似 cscript /nologo configure.js --disable-foo --enable-fun-ext 的命令。使用 --enable-foo=shared 将尝试将“foo”扩展库编译为共享的,可动态加载的模块。
最后一步是编译。只需运行命令 nmake 即可。所生成的文件(例如 .exe 和 .dll)将会放在 Release_TS 或 Debug_TS 目录下(如果编译的是线程安全版的话),或者是 Release 或 Debug 目录。
作为可选项还可以运行 PHP 的测试套件,输入 nmake test 命令。如果要做一个特定的测试,可以用 'TESTS' 变量(例如 nmake /D TESTS=ext/sqlite/tests test 将只执行 sqlite 测试)。要删除编译过程中生成的文件,可以用 nmake clean 命令。
有个很有用的选项来编译快照:--enable-snapshot-build。此选项添加了一个新的编译模式(nmake build-snap)。这将尝试编译每一个可用的扩展库(默认为共享模块方式),但是忽略个别的扩展库或 SAPI 中的编译错误。
自 PHP 5 起不支持用 DSW 文件来编译 PHP,因为有了一个更灵活的系统。不过还是可以用此方法,但要记住此系统并不经常维护,因此编译可能会有问题。不过这是在 Windows 下编译 PHP 4 的唯一方法。
第一步是配置 MVC++ 来准备编译。启动 Microsoft Visual C++,在菜单中选择 Tools => Options。在对话框中选择 directories 标签。按顺序把下拉选项选为 Executables,Includes 和 Library files。其内容应类似于:
Executable files:C:\work\win32build\bin,Cygwin 用户:C:\cygwin\bin
Include files:C:\work\win32build\include
Library files:C:\work\win32build\lib
对于初学者最好的上手方法是编译 CGI 版本:
图形界面用户,运行 VC++,选择 File => Open Workspace 菜单并选择 C:\work\php-4.x.x\win32\php4ts.dsw。接着选择 Build => Set Active Configuration 菜单并选择想要的配置,要么是 php4ts - Win32 Debug_TS 要么是 php4ts - Win32 Release_TS。最后选择 Build => Rebuild All。
命令行用户,确认要么注册了 C++ 环境变量,要么运行了 vcvars.bat,然后从 C:\work\php-4.x.x\win32 目录下运行下面任意一行命令:
msdev php4ts.dsp /MAKE "php4ts - Win32 Debug_TS"
msdev php4ts.dsp /MAKE "php4ts - Win32 Release_TS"
到这一步,应该得到一个可用的 php.exe 在 C:\work\php-4.x.x.\Debug_TS 或 Release_TS 目录下。
有可能通过编辑 main/config.win32.h 文件对编译做少量的定制。例如可以改变 php.ini 文件的默认位置,内置的扩展库,以及扩展库的默认位置。
下一步可能想要编译 CLI 版本,这是设计用于 PHP 的命令行方式。步骤和编译 CGI 版本相同,只除了要选择 php4ts_cli - Win32 Debug_TS 或者 php4ts_cli - Win32 Release_TS 项目文件。成功编译后会在 Release_TS\cli\ 或者 Debug_TS\cli\ 目录下找到 php.exe 文件。
要编译 SAPI 模块(php4isapi.dll)来将 PHP 和 Microsoft IIS 集成起来,将 active configuration 设为 php4isapi-whatever-config 并编译所需要的 dll。.
在 Windows 下安装完 PHP 和 web 服务器之后,可能想要安装一些扩展库来获得更多功能。可以通过修改 php.ini 来选择当 PHP 启动时加载哪些扩展库。也可以在脚本中通过使用 dl() 来动态加载。
PHP 扩展库的 DLL 文件都具有 php_ 前缀。
很多扩展库都内置于 Windows 版的 PHP 之中。这意味着要加载这些扩展库不需要额外的 DLL 文件和 extension 配置指令。Windows 下的 PHP 扩展库列表列出了需要或曾经需要额外 PHP DLL 文件的扩展库。下面是内置的扩展库列表:
PHP 4 中(截止到 PHP 4.3.11):BCMath,Caledar,COM,Ctype,FTP,MySQL,ODBC,Overload,PCRE,Session,Tokenizer,WDDX,XML 和 Zlib。
PHP 5 中(截止到 5.0.4)有以下修改。新增内置:DOM,LibXML,Iconv,SimpleXML,SPL 和SQLite。以下不再内置:MySQL 和 Overload。
PHP 搜索扩展库的默认位置在 PHP 4 中是 C:\php4\extensions,在 PHP 5 中是 C:\php5。要修改此项以符合用户自己的 PHP 设置,需要编辑 php.ini 文件:
需要修改 extension_dir 设置以指向用户放置扩展库的目录或者说放置 php_*.dll 文件的位置。例如:
要在 php.ini 中启用某扩展库,需要去掉该行 extension=php_*.dll 前的注释符号,将想要加载的扩展库前的分号(;)删除即可。
有些扩展库需要额外的 DLL 才能工作。其中一部分包括在发行包里,PHP 4 中在
C:\php\dlls\ 目录下,PHP 5
中在主目录下,但还有一些,例如
Oracle(php_oci8.dll)所需要的 DLL
没有绑定在发行包里。如果安装 PHP 4,将绑定的 DLL 从
C:\php\dlls 拷贝到主目录
C:\php 中。别忘了将
C:\php 放到系统路径
PATH 中去(此过程在另外的 FAQ 条目中有说明)。
某些 DLL 没有绑定在 PHP 发行包中,详情见每个扩展库的文档页。此外有关 PECL 的说明见手册页 PECL 扩展库安装。在 PECL 中有日益增加数目巨大的 PHP 扩展库,这些扩展库需要单独下载。
注意: 如果运行服务器模块版的 PHP,在修改了 php.ini 之后别忘了重新启动 web 服务器以使其改动生效。
下表说明了哪些扩展库需要额外的 DLL。
表 6-1. PHP 扩展库
| 扩展库 | 说明 | 注解 |
|---|---|---|
| php_bz2.dll | bzip2 压缩函数库 | 无 |
| php_calendar.dll | 历法转换函数库 | 自 PHP 4.0.3 起内置 |
| php_cpdf.dll | ClibPDF 函数库 | 无 |
| php_crack.dll | 密码破解函数库 | 无 |
| php_ctype.dll | ctype 家族函数库 | 自 PHP 4.3.0 起内置 |
| php_curl.dll | CURL,客户端 URL 库函数库 | 需要:libeay32.dll,ssleay32.dll(已附带) |
| php_cybercash.dll | 网络现金支付函数库 | PHP <= 4.2.0 |
| php_db.dll | DBM 函数库 | 已废弃。用 DBA 替代之(php_dba.dll) |
| php_dba.dll | DBA:数据库(dbm 风格)抽象层函数库 | 无 |
| php_dbase.dll | dBase 函数库 | 无 |
| php_dbx.dll | dbx 函数库 | |
| php_domxml.dll | DOM XML 函数库 | PHP <= 4.2.0 需要:libxml2.dll(已附带),PHP >= 4.3.0 需要:iconv.dll(已附带) |
| php_dotnet.dll | .NET 函数库 | PHP <= 4.1.1 |
| php_exif.dll | EXIF 函数库 | 需要 php_mbstring.dll。并且在 php.ini 中,php_exif.dll 必须在 php_mbstring.dll之后加载。 |
| php_fbsql.dll | FrontBase 函数库 | PHP <= 4.2.0 |
| php_fdf.dll | FDF:表单数据格式化函数库 | 需要:fdftk.dll(已附带) |
| php_filepro.dll | filePro 函数库 | 只读访问 |
| php_ftp.dll | FTP 函数库 | 自 PHP 4.0.3 起内置 |
| php_gd.dll | GD 库图像函数库 | 在 PHP 4.3.2 中删除。此外注意在 GD1 中不能用真彩色函数,用 php_gd2.dll 替代。 |
| php_gd2.dll | GD 库图像函数库 | GD2 |
| php_gettext.dll | Gettext 函数库 | PHP <= 4.2.0 需要 gnu_gettext.dll(已附带),PHP >= 4.2.3 需要 libintl-1.dll,iconv.dll(已附带)。 |
| php_hyperwave.dll | HyperWave 函数库 | 无 |
| php_iconv.dll | ICONV 字符集转换 | 需要:iconv-1.3.dll(已附带),PHP >=4.2.1 需要 iconv.dll |
| php_ifx.dll | Informix 函数库 | 需要:Informix 库 |
| php_iisfunc.dll | IIS 管理函数库 | 无 |
| php_imap.dll | IMAP,POP3 和 NNTP 函数库 | 无 |
| php_ingres.dll | Ingres II 函数库 | 需要:Ingres II 库 |
| php_interbase.dll | InterBase functions | 需要:gds32.dll(已附带) |
| php_java.dll | Java 函数库 | PHP <= 4.0.6 需要:jvm.dll(已附带) |
| php_ldap.dll | LDAP 函数库 | PHP <= 4.2.0 需要 libsasl.dll(已附带),PHP >= 4.3.0 需要 libeay32.dll,ssleay32.dll(已附带) |
| php_mbstring.dll | 多字节字符串函数库 | 无 |
| php_mcrypt.dll | Mcrypt 加密函数库 | 需要:libmcrypt.dll |
| php_mhash.dll | Mhash 函数库 | PHP >= 4.3.0 需要:libmhash.dll(已附带) |
| php_mime_magic.dll | Mimetype 函数库 | 需要:magic.mime(已附带) |
| php_ming.dll | Ming 函数库(Flash) | 无 |
| php_msql.dll | mSQL 函数库 | 需要:msql.dll(已附带) |
| php_mssql.dll | MSSQL 函数库 | 需要:ntwdblib.dll(已附带) |
| php_mysql.dll | MySQL 函数库 | PHP >= 5.0.0 需要 libmysql.dll(已附带) |
| php_mysqli.dll | MySQLi 函数库 | PHP >= 5.0.0 需要 libmysql.dll(PHP <= 5.0.2 中是 libmysqli.dll)(已附带) |
| php_oci8.dll | Oracle 8 函数库 | 需要:Oracle 8.1+ 客户端库 |
| php_openssl.dll | OpenSSL 函数库 | 需要:libeay32.dll(已附带) |
| php_oracle.dll | Oracle 函数库 | 需要:Oracle 7 客户端库 |
| php_overload.dll | 对象重载函数库 | 自 PHP 4.3.0 起内置 |
| php_pdf.dll | PDF 函数库 | 无 |
| php_pgsql.dll | PostgreSQL 函数库 | 无 |
| php_printer.dll | 打印机函数库 | 无 |
| php_shmop.dll | 共享内存函数库 | 无 |
| php_snmp.dll | SNMP 函数库 | 仅用于 Windows NT! |
| php_soap.dll | SOAP 函数库 | PHP >= 5.0.0 |
| php_sockets.dll | Socket 函数库 | 无 |
| php_sybase_ct.dll | Sybase 函数库 | 需要:Sybase 客户端库 |
| php_tidy.dll | Tidy 函数库 | PHP >= 5.0.0 |
| php_tokenizer.dll | Tokenizer 函数库 | 自 PHP 4.3.0 起内置 |
| php_w32api.dll | W32api 函数库 | 无 |
| php_xmlrpc.dll | XML-RPC 函数库 | PHP >= 4.2.1 需要 iconv.dll(已附带) |
| php_xslt.dll | XSLT 函数库 | PHP <= 4.2.0 需要 sablot.dll,expat.dll(已附带)。PHP >= 4.2.1 需要 sablot.dll,expat.dll,iconv.dll(已附带)。 |
| php_yaz.dll | YAZ 函数库 | 需要:yaz.dll(已附带) |
| php_zip.dll | Zip 文件函数库 | 只读访问 |
| php_zlib.dll | ZLib 压缩函数库 | 自 PHP 4.3.0 起内置 |
PECL 是通过 PEAR 打包系统来的 PHP 扩展库仓库,本章内容示范了怎样取得并安装 PECL 扩展。
以下指南中假定 /your/phpsrcdir/ 是 PHP 源程序的路径,extname 是 PECL 扩展库的名字。自己根据实际情况调整。此外还假定用户熟悉 pear 命令。
要使用共享扩展库,必须经过编译,安装,然后加载。以下说明的方法提供了怎样编译和安装扩展库德各种指导,但并不会自动加载它们。可以通过将其包括在 php.ini 中用 extension PHP 指令加载,或者 用 dl() 函数。
当编译 PHP 模块时,拥有各种工具(autoconf,automake,libtool 等)的已知好使的版本很重要。所需工具和所需版本的详情见匿名 CVS 说明。
下载 PECL 扩展库有几种方法,如:
PECL 网站包括有 PHP 开发组提供的不同扩展库的信息。这里的信息包括:更新记录,版本说明,需求,以及其它信息。
pear download extname
PECL 网站中列出的 PECL 扩展库的发行版本可以用 pear 命令来下载和安装。也可以指明具体的修正版。
CVS
大多数 PECL 扩展库也在 CVS 中。其 web 页面见 http://cvs.php.net/pecl/。要直接从 CVS 中下载,用以下命令,其中用户 cvsread 的密码是 phpfi:
$ cvs -d:pserver:cvsread@cvs.php.net:/repository login $ cvs -d:pserver:cvsread@cvs.php.net:/repository co pecl/extname |
Windows 下载
Windows 用户可以通过在 PHP 下载页面下载 Collection of PECL modules 来找到已编译的 PECL 可执行程序,或下载 PECL Snapshot。要在 Windows 下编译 PHP,请阅读有关章节。
和其它任何 PHP 扩展库的 DLL 一样,把 PECL 扩展库的 DLL 移动到 extension_dir 目录并将其包括入 php.ini 来安装。例如:
extension=php_extname.dll |
然后重新启动 web 服务器。
PEAR 使建立共享 PHP 扩展库更容易。用 pear 命令这样做:
$ pear install extname |
这将下载 extname 的源代码,编译之,并将 extname.so 安装到 extension_dir 中。然后 extname.so 就可以通过 php.ini 加载了。
默认情况下,pear 命令不会安装标记为 alpha 或 beta 状态的包。如果没有 stable 包可用,也可以用以下命令安装一个 beta 包:
$ pear install extname-beta |
也可以用此命令安装一个指定的版本:
$ pear install extname-0.1 |
有时候不能用 pear 安装命令。这可能是因为在防火墙后面,或者是因为想要安装的扩展库还没有 PEAR 兼容的包,例如 CVS 中尚未发布的扩展库。如果要编译这种扩展库,可以用更底层的编译工具来手工进行编译。
phpize 命令是用来准备 PHP 扩展库的编译环境的。下面例子中,扩展库的源程序位于 extname 目录中:
$ cd extname $ phpize $ ./configure $ make # make install |
成功的安装将创建 extname.so 并放置于 PHP 的扩展库目录中。需要调整 php.ini,加入 extension=extname.so 这一行之后才能使用此扩展库。
有时可能需要将扩展库静态编译到 PHP 中。这需要将扩展库源程序放入 php-src/ext/ 目录中去并告诉 PHP 编译系统来生成其配置脚本。
$ cd /your/phpsrcdir/ext $ pear download extname $ gzip -d < extname.tgz | tar -xvf - $ mv extname-x.x.x extname |
这将产生以下目录:
/your/phpsrcdir/ext/extname |
此时强制 PHP 重新生成配置脚本,然后正常编译 PHP:
$ cd /your/phpsrcdir $ rm configure $ ./buildconf --force $ ./configure --help $ ./configure --with-extname --enable-someotherext --with-foobar $ make $ make install |
注意: 要运行“buildconf”脚本,需要 autoconf 2.13 和 automake 1.4+(更新版本的 autoconf 也许能工作,但不被支持)。
是否用 --enable-extname 或 --with-extname 取决于扩展库。通常不需要外部库文件的扩展库使用 --enable。要确认的话,在 buildconf 之后运行:
$ ./configure --help | grep extname |
如果还卡着,PHP 安装邮件列表中的人可能会帮你。应该先查看归档,也许有人已经回答了另一个人提出的和你相同的问题。归档可以从支持页 http://www.php.net/support.php 访问到。要订阅 PHP 安装邮件列表,发送一封空邮件去 php-install-subscribe@lists.php.net。邮件列表地址是 php-install@lists.php.net。
如果想从邮件列表中取得帮助,请准确给出有关你的环境的必要细节(哪个操作系统,PHP 的版本,哪个 web 服务器,是否以 CGI 方式还是以服务器模块方式运行 PHP,安全模式,等等),并给出足够的代码让别人能重现和测试你碰到的问题。
如果你觉得自己发现了一个 PHP 的 bug,请提出报告。PHP 开发人员也许还不知道有问题,除非你报告了,否则有可能不会被修正。可以通过错误跟踪系统 http://bugs.php.net/ 来报告错误。请不要在邮件列表或私人信件中发送错误报告。错误跟踪系统也可以用来提出对新特性的要求。
在提交错误报告之前请先阅读怎样报告错误!
配置文件(PHP 3 中是 php3.ini,自 PHP 4 起是 php.ini)在 PHP 启动时被读取。对于服务器模块版本的 PHP,仅在 web 服务器启动时读取一次。对于 CGI 和 CLI 版本,每次调用都会读取。
php.ini 的搜索路径如下(按顺序):
SAPI 模块所指定的位置(Apache 2 中的 PHPIniDir 指令,CGI 和 CLI 中的 -c 命令行选项,NSAPI 中的 php_ini 参数,THTTPD 中的 PHP_INI_PATH 环境变量)
HKEY_LOCAL_MACHINE\SOFTWARE\PHP\IniFilePath(Windows 注册表位置)
PHPRC 环境变量
当前工作目录(对于 CLI)
web 服务器目录(对于 SAPI 模块)或 PHP 所在目录(Windows 下其它情况)
Windows 目录(C:\windows 或 C:\winnt),或 --with-config-file-path 编译时选项指定的位置
如果存在 php-SAPI.ini(SAPI 是当前所用的 SAPI 名称,因此实际文件名为 php-cli.ini 或 php-apache.ini 等),则会用它替代 php.ini。SAPI 的名称可以用 php_sapi_name() 来测定。
注意: Apache web 服务器在启动时会把目录转到根目录,这将导致 PHP 尝试在根目录下读取 php.ini,如果存在的话。
由扩展库处理的 php.ini 指令,其文档分别在各扩展库的页面。内核配置选项见附录。不过也许不是所有的 PHP 指令都在手册中有文档说明。要得到自己的 PHP 版本中的配置指令完整列表,请阅读 php.ini 文件,其中都有注释。此外,也许从 CVS 得到的最新版 php.ini 也有帮助。
例 9-1. php.ini 例子
|
自 PHP 5.1.0 起,有可能在 .ini 文件内引用已存在的 .ini 变量。例如:open_basedir = ${open_basedir} ":/new/dir"。
当使用 PHP 作为 Apache 模块时,也可以用 Apache 的配置文件(例如 httpd.conf)和 .htaccess 文件中的指令来修改 PHP 的配置设定。需要有“AllowOverride Options”或“AllowOverride All”权限才可以。
在 PHP 4 和 PHP 5 中,有几个 Apache 指令可以使用户在 Apache 配置文件内部修改 PHP 的配置。哪些指令属于 PHP_INI_ALL,PHP_INI_PERDIR 或 PHP_INI_SYSTEM 中的哪一个,请参考附录中的 php.ini 配置选项列表。
注意: 在 PHP 3 中,每个 php3.ini 中的配置设定都有相应的 Apache 指令,不过名字前要加上前缀“php3_”。
name
value设定指定的值。只能用于 PHP_INI_ALL 或 PHP_INI_PERDIR 类型的指令。要清除先前设定的值,把 value 设为 none。
注意: 不要用 php_value 设定布尔值。应该用 php_flag(见下面)。
name
on|off用来设定布尔值的配置指令。仅能用于 PHP_INI_ALL 和 PHP_INI_PERDIR 类型的指令。
name
value设定指定的指令的值。不能用于 .htaccess 文件。任何用 php_admin_value 设定的指令都不能被 .htaccess 或 virtualhost 中的指令覆盖。要清除先前设定的值,把 value 设为 none。
name
on|off用来设定布尔值的配置指令。不能用于 .htaccess 文件。任何用 php_admin_flag 设定的指令都不能被 .htaccess 或 virtualhost 中的指令覆盖。
例 9-2. Apache 配置例子
|
| 小心 |
PHP 常量不存在于 PHP 之外。例如在 httpd.conf 中不能使用 PHP 常量如 E_ALL 或 E_NOTICE 来设定 error_reporting 指令,因为其无意义,实际等于 0。应该用相应的掩码值来替代。这些常量可以在 php.ini 中使用。 |
在 Windows 下运行 PHP 时,可以用 Windows 注册表以目录为单位来修改配置。配置值存放于注册表项 HKLM\SOFTWARE\PHP\Per Directory Values 下面,子项对应于路径名。例如对于目录 c:\inetpub\wwwroot 的配置值会存放于 HKLM\SOFTWARE\PHP\Per Directory Values\c\inetpub\wwwroot 项下面。其中的设定对于任何位于此目录及其任何子目录的脚本都有效。项中的值的名称是 PHP 配置指令的名字,值的数据是字符串格式的指令值。值中的 PHP 常量不被解析。不过只有可修改范围是 PHP_INI_USER 的配置值可以用此方法设定,PHP_INI_PERDIR 的值就不行。
无论怎样运行 PHP,都可以在脚本中通过 ini_set() 而在运行时修改某个值。更多信息见手册中 ini_set() 的页面。
如果对自己系统中的配置设定及其当前值的完整列表感兴趣,可以运行 phpinfo() 函数并查看其结果的页面。也可以在运行时用 ini_get() 或 get_cfg_var() 取得个别配置指令的值。
当 PHP 解析一个文件时,会寻找开始和结束标记,标记告诉 PHP 开始和停止解释其中的代码。此种方式的解析可以使 PHP 嵌入到各种不同的文档中,凡是在一对开始和结束标记之外的内容都会被 PHP 解析器忽略。大多数情况下 PHP 都是嵌入在 HTML 文档中的,如下例所示。
<p>This is going to be ignored.</p> <?php echo 'While this is going to be parsed.'; ?> <p>This will also be ignored.</p> |
还可以用更高级的结构:
可以在 PHP 中使用四对不同的开始和结束标记。其中两种,<?php ?> 和 <script language="php"> </script> 总是可用的。另两种是短标记和 ASP 风格标记,可以在 php.ini 配置文件中打开或关闭。尽管有些人觉得短标记和 ASP 风格标记很方便,但移植性较差,通常不推荐。
注意: 此外注意如果将 PHP 嵌入到 XML 或 XHTML 中则需要使用 <?php ?> 以保持符合标准。
例 10-2. PHP 开始和结束标记
|
上例中的 1 和 2 总是可用的,其中 1 是最常用,并建议使用的。
短标记(上例 3)仅在通过 php.ini 配置文件中的指令
short_open_tag
打开后才可用,或者在 PHP 编译时加入了
--enable-short-tags 选项。
注意: 如果用 PHP 3 还可以通过 short_tags() 函数激活使用短标记。此方法只适用于 PHP 3!
ASP 风格标记(上例 4)仅在通过 php.ini 配置文件中的指令 asp_tags 打开后才可用。
注意: 对 ASP 风格标记的支持是 3.0.4 版添加的。
注意: 在以下情况应避免使用短标记:开发需要发行的程序或者库,或者在用户不能控制的服务器上开发。因为目标服务器可能不支持短标记。为了代码的移植及发行,确保不要使用短标记。
同 C 或 Perl 一样,PHP 需要在每个语句后用分号结束指令。一段 PHP 代码中的结束标记隐含表示了一个分号;在一个 PHP 代码段中的最后一行可以不用分号结束。如果后面还有新行,则代码段的结束标记包含了行结束。
PHP 支持 C,C++ 和 Unix Shell 风格(Perl 风格)的注释。例如:
<?php
echo "This is a test"; // This is a one-line c++ style comment
/* This is a multi line comment
yet another line of comment */
echo "This is yet another test";
echo 'One Final Test'; # This is a one-line shell-style comment
?> |
单行注释仅仅注释到行末或者当前的 PHP 代码块,视乎哪个首先出现。这意味着在 // ... ?> 或者 # ... ?> 之后的 HTML 代码将被显示出来:?> 跳出了 PHP 模式并返回了 HTML 模式,// 或 # 并不能影响到这一点。如果启用了 asp_tags 配置选项,其行为和 // %> 或 # %> 相同。不过,</script> 标记在单行注释中不会跳出 PHP 模式。
<h1>This is an <?php # echo "simple";?> example.</h1> <p>The header above will say 'This is an example'. |
C 风格的注释在碰到第一个 */ 时结束。要确保不要嵌套 C 风格的注释。试图注释掉一大块代码时很容易出现该错误。
PHP 支持八种原始类型。
四种标量类型:
两种复合类型: 最后是两种特殊类型: 为了确保代码的易读性,本手册还介绍了一些伪类型: 可能还会读到一些关于“双精度(double)”类型的参考。实际上 double 和 float 是相同的,由于一些历史的原因,这两个名称同时存在。变量的类型通常不是由程序员设定的,确切地说,是由 PHP 根据该变量使用的上下文在运行时决定的。
注意: 如果想查看某个表达式的值和类型,用 var_dump()。
注意: 如果只是想得到一个易读懂的类型的表达方式用于调试,用 gettype()。要查看某个类型,不要用 gettype(),而用 is_type 函数。以下是一些范例:
<?php $bool = TRUE; // a boolean $str = "foo"; // a string $int = 12; // an integer echo gettype($bool); // prints out "boolean" echo gettype($str); // prints out "string" // If this is an integer, increment it by four if (is_int($int)) { $int += 4; } // If $bool is a string, print it out // (does not print out anything) if (is_string($bool)) { echo "String: $bool"; } ?>
如果要将一个变量强制转换为某类型,可以对其使用强制转换或者 settype() 函数。
注意变量根据其当时的类型在特定场合下会表现出不同的值。更多信息见类型戏法。此外,你还可以参考 PHP 类型比较表看不同类型相互比较的例子。
这是最简单的类型。boolean 表达了真值,可以为 TRUE 或 FALSE。
注意: 布尔类型是 PHP 4 引进的。
要明示地将一个值转换成 boolean,用 (bool) 或者 (boolean) 来强制转换。但是很多情况下不需要用强制转换,因为当运算符,函数或者流程控制需要一个 boolean 参数时,该值会被自动转换。
参见类型戏法。
当转换为 boolean 时,以下值被认为是 FALSE:
所有其它值都被认为是 TRUE(包括任何资源)。| 警告 |
-1 和其它非零值(不论正负)一样,被认为是 TRUE! |
<?php var_dump((bool) ""); // bool(false) var_dump((bool) 1); // bool(true) var_dump((bool) -2); // bool(true) var_dump((bool) "foo"); // bool(true) var_dump((bool) 2.3e5); // bool(true) var_dump((bool) array(12)); // bool(true) var_dump((bool) array()); // bool(false) var_dump((bool) "false"); // bool(true) ?> |
一个 integer 是集合 Z = {..., -2, -1, 0, 1, 2, ...} 中的一个数。
参见任意长度整数(GMP),浮点数和任意精度数学库(BCMath)。
整型值可以用十进制,十六进制或八进制符号指定,前面可以加上可选的符号(- 或者 +)。
如果用八进制符号,数字前必须加上 0(零),用十六进制符号数字前必须加上 0x。
如果给定的一个数超出了 integer 的范围,将会被解释为 float。同样如果执行的运算结果超出了 integer 范围,也会返回 float。
<?php $large_number = 2147483647; var_dump($large_number); // 输出为:int(2147483647) $large_number = 2147483648; var_dump($large_number); // 输出为:float(2147483648) // 同样也适用于十六进制表示的整数: var_dump( 0x80000000 ); // 输出为:float(2147483648) $million = 1000000; $large_number = 50000 * $million; var_dump($large_number); // 输出为:float(50000000000) ?> |
| 警告 |
不幸的是 PHP 中有个 bug,因此当有负数参与时结果并不总是正确。例如当运算 -50000 * $million 时结果是 -429496728。不过当两个运算数都是正数时就没问题。 这个问题已经在 PHP 4.1.0 中解决了。 |
要明示地将一个值转换为 integer,用 (int) 或 (integer) 强制转换。不过大多数情况下都不需要强制转换,因为当运算符,函数或流程控制需要一个 integer 参数时,值会自动转换。还可以通过函数 intval() 来将一个值转换成整型。
参见类型戏法。
浮点数(也叫浮点数,双精度数或实数)可以用以下任何语法定义:
形式上:LNUM [0-9]+
DNUM ([0-9]*[\.]{LNUM}) | ({LNUM}[\.][0-9]*)
EXPONENT_DNUM ( ({LNUM} | {DNUM}) [eE][+-]? {LNUM}) |
string 是一系列字符。在 PHP 中,字符和字节一样,也就是说,一共有 256 种不同字符的可能性。这也暗示 PHP 对 Unicode 没有本地支持。请参阅函数 utf8_encode() 和 utf8_decode() 以了解有关 Unicode 支持。
注意: 一个字符串变得非常巨大也没有问题,PHP 没有给字符串的大小强加实现范围,所以完全没有理由担心长字符串。
字符串可以用三种字面上的方法定义。
指定一个简单字符串的最简单的方法是用单引号(字符 ')括起来。
要表示一个单引号,需要用反斜线(\)转义,和很多其它语言一样。如果在单引号之前或字符串结尾需要出现一个反斜线,需要用两个反斜线表示。注意如果试图转义任何其它字符,反斜线本身也会被显示出来!所以通常不需要转义反斜线本身。
注意: 在 PHP 3 中,此情况下将发出一个 E_NOTICE 级的警告。
注意: 和其他两种语法不同,单引号字符串中出现的变量和转义序列不会被变量的值替代。
<?php echo 'this is a simple string'; echo 'You can also have embedded newlines in strings this way as it is okay to do'; // Outputs: Arnold once said: "I'll be back" echo 'Arnold once said: "I\'ll be back"'; // Outputs: You deleted C:\*.*? echo 'You deleted C:\\*.*?'; // Outputs: You deleted C:\*.*? echo 'You deleted C:\*.*?'; // Outputs: This will not expand: \n a newline echo 'This will not expand: \n a newline'; // Outputs: Variables do not $expand $either echo 'Variables do not $expand $either'; ?> |
如果用双引号(")括起字符串,PHP 懂得更多特殊字符的转义序列:
表 11-1. 转义字符
| 序列 | 含义 |
|---|---|
| \n | 换行(LF 或 ASCII 字符 0x0A(10)) |
| \r | 回车(CR 或 ASCII 字符 0x0D(13)) |
| \t | 水平制表符(HT 或 ASCII 字符 0x09(9)) |
| \\ | 反斜线 |
| \$ | 美元符号 |
| \" | 双引号 |
| \[0-7]{1,3} | 此正则表达式序列匹配一个用八进制符号表示的字符 |
| \x[0-9A-Fa-f]{1,2} | 此正则表达式序列匹配一个用十六进制符号表示的字符 |
此外,如果试图转义任何其它字符,反斜线本身也会被显示出来!在 PHP 5.1.1 之前,\{$var} 中的反斜线不会被显示出来。
双引号字符串最重要的一点是其中的变量名会被变量值替代。细节参见字符串解析。
另一种给字符串定界的方法使用定界符语法(“<<<”)。应该在 <<< 之后提供一个标识符,然后是字符串,然后是同样的标识符结束字符串。
结束标识符必须从行的第一列开始。同样,标识符也必须遵循 PHP 中其它任何标签的命名规则:只能包含字母数字下划线,而且必须以下划线或非数字字符开始。
| 警告 | |
很重要的一点必须指出,结束标识符所在的行不能包含任何其它字符,可能除了一个分号(;)之外。这尤其意味着该标识符不能被缩进,而且在分号之前和之后都不能有任何空格或制表符。同样重要的是要意识到在结束标识符之前的第一个字符必须是你的操作系统中定义的换行符。例如在 Macintosh 系统中是 \r。 如果破坏了这条规则使得结束标识符不“干净”,则它不会被视为结束标识符,PHP 将继续寻找下去。如果在这种情况下找不到合适的结束标识符,将会导致一个在脚本最后一行出现的语法错误。 不能用定界符语法初始化类成员。用其它字符串语法替代。 |
定界符文本表现的就和双引号字符串一样,只是没有双引号。这意味着在定界符文本中不需要转义引号,不过仍然可以用以上列出来的转义代码。变量会被展开,但当在定界符文本中表达复杂变量时和字符串一样同样也要注意。
例 11-4. 定界符字符串例子
|
注意: 定界符支持是 PHP 4 中加入的。
当用双引号或者定界符指定字符串时,其中的变量会被解析。
有两种语法,一种简单的和一种复杂的。简单语法最通用和方便,它提供了解析变量,数组值,或者对象属性的方法。
复杂语法是 PHP 4 引进的,可以用花括号括起一个表达式。
如果遇到美元符号($),解析器会尽可能多地取得后面的字符以组成一个合法的变量名。如果想明示指定名字的结束,用花括号把变量名括起来。
<?php
$beer = 'Heineken';
echo "$beer's taste is great"; // works, "'" is an invalid character for varnames
echo "He drank some $beers"; // won't work, 's' is a valid character for varnames
echo "He drank some ${beer}s"; // works
echo "He drank some {$beer}s"; // works
?> |
同样也可以解析数组索引或者对象属性。对于数组索引,右方括号(])标志着索引的结束。对象属性则和简单变量适用同样的规则,尽管对于对象属性没有像变量那样的小技巧。
<?php
// These examples are specific to using arrays inside of strings.
// When outside of a string, always quote your array string keys
// and do not use {braces} when outside of strings either.
// Let's show all errors
error_reporting(E_ALL);
$fruits = array('strawberry' => 'red', 'banana' => 'yellow');
// Works but note that this works differently outside string-quotes
echo "A banana is $fruits[banana].";
// Works
echo "A banana is {$fruits['banana']}.";
// Works but PHP looks for a constant named banana first
// as described below.
echo "A banana is {$fruits[banana]}.";
// Won't work, use braces. This results in a parse error.
echo "A banana is $fruits['banana'].";
// Works
echo "A banana is " . $fruits['banana'] . ".";
// Works
echo "This square is $square->width meters broad.";
// Won't work. For a solution, see the complex syntax.
echo "This square is $square->width00 centimeters broad.";
?> |
对于任何更复杂的情况,应该使用复杂语法。
不是因为语法复杂而称其为复杂,而是因为用此方法可以包含复杂的表达式。
事实上,用此语法可以在字符串中包含任何在名字空间的值。仅仅用和在字符串之外同样的方法写一个表达式,然后用 { 和 } 把它包含进来。因为不能转义“{”,此语法仅在 $ 紧跟在 { 后面时被识别(用“{\$”来得到一个字面上的“{$”)。用一些例子可以更清晰:
<?php
// Let's show all errors
error_reporting(E_ALL);
$great = 'fantastic';
// 不行,输出为:This is { fantastic}
echo "This is { $great}";
// 可以,输出为:This is fantastic
echo "This is {$great}";
echo "This is ${great}";
// Works
echo "This square is {$square->width}00 centimeters broad.";
// Works
echo "This works: {$arr[4][3]}";
// This is wrong for the same reason as $foo[bar] is wrong
// outside a string. In otherwords, it will still work but
// because PHP first looks for a constant named foo, it will
// throw an error of level E_NOTICE (undefined constant).
echo "This is wrong: {$arr[foo][3]}";
// Works. When using multi-dimensional arrays, always use
// braces around arrays when inside of strings
echo "This works: {$arr['foo'][3]}";
// Works.
echo "This works: " . $arr['foo'][3];
echo "You can even write {$obj->values[3]->name}";
echo "This is the value of the var named $name: {${$name}}";
?> |
字符串中的字符可以通过在字符串之后用花括号指定所要字符从零开始的偏移量来访问和修改。
注意: 为了向下兼容,仍然可以用方括号。不过此语法自 PHP 4 起已过时。
例 11-5. 一些字符串例子
|
字符串可以用“.”(点)运算符连接。注意这里不能用“+”(加)运算符。更多信息参见字符串运算符。
有很多实用函数来改变字符串。
普通函数见字符串函数一节,高级搜索和替换见正则表达式函数(两种风格:Perl 和 POSIX 扩展)。
还有 URL 字符串函数,以及加密/解密字符串的函数(mcrypt 和 mhash)。
最后,如果还是找不到想要的函数,参见字符类型函数。
可以用 (string) 标记或者 strval() 函数将一个值转换为字符串。当某表达式需要字符串时,字符串的转换会在表达式范围内自动完成。例如当使用 echo() 或者 print() 函数时,或者将一个变量值与一个字符串进行比较的时候。阅读手册中有关类型和类型戏法中的部分有助于更清楚一些。参见 settype()。
布尔值 TRUE 将被转换为字符串 "1",而值 FALSE 将被表示为 ""(即空字符串)。这样就可以随意地在布尔值和字符串之间进行比较。
整数或浮点数数值在转换成字符串时,字符串由表示这些数值的数字字符组成(浮点数还包含有指数部分)。
数组将被转换成字符串 "Array",因此无法通过 echo() 或者 print() 函数来输出数组的内容。请参考下文以获取更多提示。
对象将被转换成字符串 "Object"。如果因为调试需要,需要将对象的成员变量打印出来,请阅读下文。如果希望得到该对象所依附的类的名称,请使用函数 get_class()。自 PHP 5 起,如果合适可以用 __toString() 方法。
资源类型总是以 "Resource id #1" 的格式被转换成字符串,其中 1 是 PHP 在运行时给资源指定的唯一标识。如果希望获取资源的类型,请使用函数 get_resource_type()。
NULL 将被转换成空字符串。
正如以上所示,将数组、对象或者资源打印出来,并不能提供任何关于这些值本身的有用的信息。请参阅函数 print_r() 和 var_dump(),对于调试来说,这些是更好的打印值的方法。
可以将 PHP 的值转换为字符串以永久地储存它们。这种方法被称为序列化,可以用函数 serialize() 来完成该操作。如果在安装 PHP 时建立了 WDDX 支持,还可以将 PHP 的值序列化为 XML 结构。
当一个字符串被当作数字来求值时,根据以下规则来决定结果的类型和值。
如果包括“.”,“e”或“E”其中任何一个字符的话,字符串被当作 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) 的部分。
如果想测试本节中的任何例子,可以拷贝和粘贴这些例子并且加上下面这一行自己看看会发生什么:
不要指望在将一个字符转换成整型时能够得到该字符的编码(可能也会在 C 中这么做)。如果希望在字符编码和字符之间转换,请使用 ord() 和 chr() 函数。
PHP 中的数组实际上是一个有序图。图是一种把 values 映射到 keys 的类型。此类型在很多方面做了优化,因此可以把它当成真正的数组来使用,或列表(矢量),散列表(是图的一种实现),字典,集合,栈,队列以及更多可能性。因为可以用另一个 PHP 数组作为值,也可以很容易地模拟树。
解释这些结构超出了本手册的范围,但对于每种结构至少会发现一个例子。要得到这些结构的更多信息,建议参考有关此广阔主题的外部著作。
可以用 array() 语言结构来新建一个 array。它接受一定数量用逗号分隔的 key => value 参数对。
array( [key =>]
value
, ...
)
// key 可以是 integer 或者 string
// value 可以是任何值 |
key 可以是 integer 或者 string。如果键名是一个
integer 的标准表达方法,则被解释为整数(例如 "8" 将被解释为
8,而 "08" 将被解释为 "08")。key
中的浮点数被取整为 integer。PHP
中没有不同的数字下标和关联下标数组,数组的类型只有一种,它可以同时包含整型和字符串型的下标。
值可以是任何值。
<?php
$arr = array("somearray" => array(6 => 5, 13 => 9, "a" => 42));
echo $arr["somearray"][6]; // 5
echo $arr["somearray"][13]; // 9
echo $arr["somearray"]["a"]; // 42
?> |
如果对给出的值没有指定键名,则取当前最大的整数索引值,而新的键名将是该值加一。如果指定的键名已经有了值,则该值会被覆盖。
<?php // This array is the same as ... array(5 => 43, 32, 56, "b" => 12); // ...this array array(5 => 43, 6 => 32, 7 => 56, "b" => 12); ?> |
| 警告 |
自 PHP 4.3.0 起,上述的索引生成方法改变了。如今如果给一个当前最大键名是负值的数组添加一个新值,则新生成的的索引将为零(0)。以前新生成的索引为当前最大索引加一,和正值的索引相同。 |
使用 TRUE 作为键名将使 integer 1 成为键名。使用 FALSE 作为键名将使 integer 0 成为键名。使用 NULL 作为键名将等同于使用空字符串。使用空字符串作为键名将新建(或覆盖)一个用空字符串作为键名的值,这和用空的方括号不一样。
不能用数组和对象作为键名。这样做会导致一个警告:Illegal offset type。
可以通过明示地设定值来改变一个现有的数组。
这是通过在方括号内指定键名来给数组赋值实现的。也可以省略键名,在这种情况下给变量名加上一对空的方括号(“[]”)。
$arr[key] = value; $arr[] = value; // key 可以是 integer 或者 string // value 可以为任何值。 |
$arr 还不存在,将会新建一个。这也是一种定义数组的替换方法。要改变一个值,只要给它赋一个新值。如果要删除一个键名/值对,要对它用 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
?> |
注意: 如上所述,如果给出方括号但没有指定键名,则取当前最大整数索引值,新的键名将是该值 + 1。如果当前还没有整数索引,则键名将为 0。如果指定的键名已经有值了,该值将被覆盖。
警告 自 PHP 4.3.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 )
有相当多的实用函数作用于数组,参见数组函数一节。
注意: unset() 函数允许取消一个数组中的键名。要注意数组将不会重建索引。
foreach 控制结构是专门用于数组的。它提供了一个简单的方法来遍历数组。
应该始终在用字符串表示的数组索引上加上引号。例如用 $foo['bar'] 而不是 $foo[bar]。但是为什么 $foo[bar] 错了呢?可能在老的脚本中见过如下语法:
这样是错的,但可以正常运行。那么为什么错了呢?原因是此代码中有一个未定义的常量(bar)而不是字符串('bar'-注意引号),而 PHP 可能会在以后定义此常量,不幸的是你的代码中有同样的名字。它能运行,是因为 PHP 自动将裸字符串(没有引号的字符串且不对应于任何已知符号)转换成一个其值为该裸字符串的正常字符串。例如,如果没有常量定义为 bar,PHP 将把它替代为 'bar' 并使用之。注意: 这并不意味着总是给键名加上引号。用不着给键名为常量或变量的加上引号,否则会使 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.php on line 10 Bad: Good: 1 Notice: Undefined index: $i in /path/to/script.php on line 12 Bad: Good: 1 Checking 1: Notice: Undefined index: $i in /path/to/script.php on line 10 Bad: Good: 2 Notice: Undefined index: $i in /path/to/script.php on line 12 Bad: Good: 2
演示此效应的更多例子:
<?php
// 显示所有错误
error_reporting(E_ALL);
$arr = array('fruit' => 'apple', 'veggie' => 'carrot');
// 正确
print $arr['fruit']; // apple
print $arr['veggie']; // carrot
// 不正确。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
// Let's define a constant to demonstrate what's going on. We
// will assign value 'veggie' 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 error here
print "Hello $arr[fruit]"; // Hello apple
// With one exception, braces surrounding arrays within strings
// allows constants to be looked for
print "Hello {$arr[fruit]}"; // Hello carrot
print "Hello {$arr['fruit']}"; // Hello apple
// This will not work, results 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 autoglobals 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 也可以用已知常量,可能之前已经见过 E_*。<?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"; ?> |
<?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"; ?> |
如同在以上例子中解释的那样,$foo[bar] 起作用但其实是错误的。它起作用是因为根据语法的预期,bar 被当成了一个常量表达式。然而,在这个例子中不存在名为 bar 的常量。PHP 就假定指的是字面上的 bar,也就是字符串 "bar",但忘记加引号了。
在未来的某一时刻,PHP 开发小组可能会想新增一个常量或者关键字,或者用户可能希望以后在自己的程序中引入新的常量,那就有麻烦了。例如已经不能这样用 empty 和 default 这两个词了,因为他们是保留字。
注意: 重申一次,在双引号字符串中,不给索引加上引号是合法的因此 "$foo[bar]"是合法的。至于为什么参见以上的例子和字符串中的变量解析中的解释。
对于任何的类型:整型、浮点、字符串、布尔和资源,如果将一个值转换为数组,将得到一个仅有一个元素的数组(其下标为 0),该元素即为此标量的值。
如果将一个对象转换成一个数组,所得到的数组的元素为该对象的属性(成员变量),其键名为成员变量名。
如果将一个 NULL 值转换成数组,将得到一个空数组。
PHP 中的数组类型有非常多的用途,因此这里有一些例子展示数组的完整威力。
<?php
// this
$a = array( 'color' => 'red',
'taste' => 'sweet',
'shape' => 'round',
'name' => 'apple',
4 // key will be 0
);
// is completely equivalent with
$a['color'] = 'red';
$a['taste'] = 'sweet';
$a['shape'] = 'round';
$a['name'] = 'apple';
$a[] = 4; // key will be 0
$b[] = 'a';
$b[] = 'b';
$b[] = 'c';
// will result in the array array(0 => 'a' , 1 => 'b' , 2 => 'c'),
// or simply array('a', 'b', 'c')
?> |
例 11-6. 使用 array()
|
直接改变数组的值在 PHP 5 中可以通过引用传递来做到。之前的版本需要需要采取别的方法:
例 11-8. 集合
上例将输出:
|
本例产生一个下标从 1 开始的数组。
数组是有序的。也可以使用不同的排序函数来改变顺序。更多信息参见数组函数。可以用 count() 函数来数出数组中元素的个数。
因为数组中的值可以为任意值,也可是另一个数组。这样可以产生递归或多维数组。
例 11-12. 递归和多维数组
|
需要注意数组的赋值总是会涉及到值的拷贝。这还意味着在 current() 以及类似函数中使用的内部数组指针会被重置。需要在复制数组时用引用符号(&)。
如果将一个对象转换成对象,它将不会有任何变化。如果其它任何类型的值被转换成对象,内置类 stdClass 的一个实例将被建立。如果该值为 NULL,则新的实例为空。数组转换成对象将使键名成为属性名并具有相对应的值。对于任何其它的值,名为 scalar 的成员变量将包含该值。
特殊的 NULL 值表示一个变量没有值。NULL 类型唯一可能的值就是 NULL。
注意: NULL 类型是 PHP 4 引进的。
在下列情况下一个变量被认为是 NULL:
被赋值为 NULL。
尚未被赋值。
被 unset()。
有些诸如 call_user_function() 或 usort() 的函数接受用户自定义的函数作为一个参数。Callback 函数不仅可以是一个简单的函数,它还可以是一个对象的方法,包括静态类的方法。
一个 PHP 函数用函数名字符串来传递。可以传递任何内置的或者用户自定义的函数,除了 array(),echo(),empty(),eval(),exit(),isset(),list(),print() 和 unset()。
一个对象的方法以数组的形式来传递,数组的下标 0 指明对象名,下标 1 指明方法名。
对于没有实例化为对象的静态类,要传递其方法,将数组 0 下标指明的对象名换成该类的名称即可。
例 11-13. Callback 函数实例
|
PHP 在变量定义中不需要(或不支持)明示的类型定义;变量类型是根据使用该变量的上下文所决定的。也就是说,如果把一个字符串值赋给变量
var,var
就成了一个字符串。如果又把一个整型值赋给
var,那它就成了一个整数。
PHP 的自动类型转换的一个例子是加号“+”。如果任何一个运算数是浮点数,则所有的运算数都被当成浮点数,结果也是浮点数。否则运算数会被解释为整数,结果也是整数。注意这并没有改变这些运算数本身的类型;改变的仅是这些运算数如何被求值。
<?php $foo = "0"; // $foo is string (ASCII 48) $foo += 2; // $foo is now an integer (2) $foo = $foo + 1.3; // $foo is now a float (3.3) $foo = 5 + "10 Little Piggies"; // $foo is integer (15) $foo = 5 + "10 Small Pigs"; // $foo is integer (15) ?> |
如果上面两个例子看上去古怪的话,参见字符串转换为数值。
如果要强制将一个变量当作某种类型来求值,参见类型强制转换一节。如果要改变一个变量的类型,参见 settype()。
如果想要测试本节中任何例子的话,可以用 var_dump() 函数。
注意: 数组的自动转换行为目前没有定义。
由于一些历史原因,PHP 支持通过偏移量进行的字符串索引,这和数组索引的语法一样。以上的例子就产生了一个问题:$a 应该变成一个第一个元素是“f”的数组呢,还是“f”成了字符串 $a 的第一个字符?
目前版本的 PHP 将以上第二个赋值理解成字符串的偏移量标识,即 $a 变成了 "f",尽管如此,这种自动转换的地结果应该被认为未定义。PHP 4 引入了新的花括号语法来访问字符串的字符,请使用该语法来替代以上的操作:
请参阅访问和修改字符串中的字符一节以获取更多信息。
PHP 中的类型强制转换和 C 中的非常像:在要转换的变量之前加上用括号括起来的目标类型。
允许的强制转换有:
(int),(integer) - 转换成整型
(bool),(boolean) - 转换成布尔型
(float),(double),(real) - 转换成浮点型
(string) - 转换成字符串
(array) - 转换成数组
(object) - 转换成对象
注意在括号内允许有空格和制表符,所以下面两个例子功能相同:
注意: 为了将一个变量还原为字符串,还可以将变量放置在双引号中。
当在某些类型之间强制转换时确切地会发生什么可能不是很明显。更多信息见如下小节:
PHP 中的变量用一个美元符号后面跟变量名来表示。变量名是区分大小写的。
变量名与 PHP 中其它的标签一样遵循相同的规则。一个有效的变量名由字母或者下划线开头,后面跟上任意数量的字母,数字,或者下划线。按照正常的正则表达式,它将被表述为:'[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*'。
注意: 在此所说的字母是 a-z,A-Z,以及 ASCII 字符从 127 到 255(0x7f-0xff)。
有关变量的函数信息见变量函数。
<?php $var = 'Bob'; $Var = 'Joe'; echo "$var, $Var"; // 输出 "Bob, Joe" $4site = 'not yet'; // 非法变更名;以数字开头 $_4site = 'not yet'; // 合法变量名;以下划线开头 $i站点is = 'mansikka'; // 合法变量名;可以用中文 ?> |
PHP 3 中,变量总是传值赋值。那也就是说,当将一个表达式的值赋予一个变量时,整个原始表达式的值被赋值到目标变量。这意味着,例如,当一个变量的值赋予另外一个变量时,改变其中一个变量的值,将不会影响到另外一个变量。有关这种类型的赋值操作,请参阅表达式一章。
PHP 4 提供了另外一种方式给变量赋值:引用赋值。这意味着新的变量简单的引用(换言之,“成为其别名” 或者 “指向”)了原始变量。改动新的变量将影响到原始变量,反之亦然。
使用引用赋值,简单地将一个 & 符号加到将要赋值的变量前(源变量)。例如,下列代码片断将输出“My name is Bob”两次:
<?php $foo = 'Bob'; // Assign the value 'Bob' to $foo $bar = &$foo; // Reference $foo via $bar. $bar = "My name is $bar"; // Alter $bar... echo $bar; echo $foo; // $foo is altered too. ?> |
有一点重要事项必须指出,那就是只有有名字的变量才可以引用赋值。
<?php
$foo = 25;
$bar = &$foo; // This is a valid assignment.
$bar = &(24 * 7); // Invalid; references an unnamed expression.
function test()
{
return 25;
}
$bar = &test(); // Invalid.
?> |
虽然在 PHP 中并不需要初始化变量,但这是个好习惯。未初始化的变量具有其类型的默认值 - FALSE,零,空字符串或者空数组。
依赖未初始化变量的默认值在某些情况下会有问题,例如把一个文件包含到另一个之中时碰上相同的变量名。另外把 register_globals 打开是一个主要的安全隐患。E_NOTICE 级别的错误会在碰上未初始化的变量时发出,但是在向一个未初始化的数组附加单元时不会。isset() 语言结构可以用来检测一个变量是否已被初始化。
PHP 提供了大量的预定义变量。由于许多变量依赖于运行的服务器的版本和设置,及其它因素,所以并没有详细的说明文档。一些预定义变量在 PHP 以命令行形式运行时并不生效。有关这些变量的详细列表,请参阅预定义变量一章。
| 警告 |
PHP 4.2.0 以及后续版本中,PHP 指令 register_globals 的默认值为
off。这是 PHP 的一个主要变化。让 register_globals 的值为
off 将影响到预定义变量集在全局范围内的有效性。例如,为了得到
更多相关信息,请阅读 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 起,长格式的 PHP
预定义变量可以通过设置
register_long_arrays 来屏蔽。
可变变量: 超级全局变量不能被用作可变变量。
注意: 尽管超全局变量和 HTTP_*_VARS 同时存在。但是他们并不是同一个变量,所以改变一个的值并不会对另一个产生影响。
如果某些 variables_order 中的变量没有设定,它们的对应的 PHP 预定义数组也是空的。
PHP 超全局变量
包含一个引用指向每个当前脚本的全局范围内有效的变量。该数组的键名为全局变量的名称。从
PHP 3 开始存在 $GLOBALS 数组。
变量由 web 服务器设定或者直接与当前脚本的执行环境相关联。类似于旧数组 $HTTP_SERVER_VARS
数组(依然有效,但反对使用)。
经由 URL 请求提交至脚本的变量。类似于旧数组 $HTTP_GET_VARS
数组(依然有效,但反对使用)。
经由 HTTP POST 方法提交至脚本的变量。类似于旧数组 $HTTP_POST_VARS
数组(依然有效,但反对使用)。
经由 HTTP Cookies 方法提交至脚本的变量。类似于旧数组 $HTTP_COOKIE_VARS
数组(依然有效,但反对使用)。
经由 HTTP POST 文件上传而提交至脚本的变量。类似于旧数组 $HTTP_POST_FILES
数组(依然有效,但反对使用)。详细信息请参阅 POST 方法上传。
执行环境提交至脚本的变量。类似于旧数组 $HTTP_ENV_VARS
数组(依然有效,但反对使用)。
经由 GET,POST 和 COOKIE 机制提交至脚本的变量,因此该数组并不值得信任。所有包含在该数组中的变量的存在与否以及变量的顺序均按照 php.ini 中的 variables_order 配置指示来定义。此数组在 PHP 4.1.0 之前没有直接对应的版本。参见 import_request_variables()。
| 小心 |
自 PHP 4.3.0 起, |
注意: 当运行于命令行模式时,此数组将不会包含
argv和argc条目;它们已经存在于数组$_SERVER中。
当前注册给脚本会话的变量。类似于旧数组
$HTTP_SESSION_VARS 数组(依然有效,但反对使用)。详细信息,请参照
Session 处理函数章节。
变量的范围即它定义的上下文背景(也就是它的生效范围)。大部分的 PHP 变量只有一个单独的范围。这个单独的范围跨度同样包含了 include 和 require 引入的文件。例如:
这里变量 $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 的例子:
以上脚本的输出将是“3”。在函数中申明了全局变量
$a 和 $b,任何变量的所有引用变量都会指向到全局变量。对于一个函数能够申明的全局变量的最大个数,PHP 没有限制。
在全局范围内访问变量的第二个办法,是用特殊的 PHP 自定义
$GLOBALS 数组。前面的例子可以写成:
在 $GLOBALS
数组中,每一个变量为一个元素,键名对应变量名,值对应变量的内容。$GLOBALS
之所以在全局范围内存在,是因为 $GLOBALS 是一个超全局变量。以下范例显示了超全局变量的用处:
变量范围的另一个重要特性是静态变量(static variable)。静态变量仅在局部函数域中存在,但当程序执行离开此作用域时,其值并不丢失。看看下面的例子:
本函数没什么用处,因为每次调用时都会将
$a 的值设为 0 并输出
"0"。将变量加一的 $a++
没有作用,因为一旦退出本函数则变量
$a 就不存在了。要写一个不会丢失本次计数值的计数函数,要将变量
$a 定义为静态的:
现在,每次调用 Test() 函数都会输出
$a 的值并加一。
静态变量也提供了一种处理递归函数的方法。递归函数是一种调用自己的函数。写递归函数时要小心,因为可能会无穷递归下去。必须确保有充分的方法来中止递归。一下这个简单的函数递归计数到
10,使用静态变量
$count 来判断何时停止:
在 Zend 引擎 1 代,它驱动了 PHP4,对于变量的 static 和 global 定义是以 references 的方式实现的。例如,在一个函数域内部用 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() 函数时其值并没有被记住。
有时候使用可变变量名是很方便的。就是说,一个变量的变量名可以动态的设置和使用。一个普通的变量通过声明来设置,例如:
一个可变变量获取了一个普通变量的值作为这个可变变量的变量名。在上面的例子中 hello 使用了两个美元符号($)以后,就可以作为一个可变变量的变量了。例如:
这时,两个变量都被定义了:$a 的内容是“hello”并且
$hello 的内容是“world”。因此,可以表述为:
以下写法更准确并且会输出同样的结果:
它们都会输出:hello world。
要将可变变量用于数组,必须解决一个模棱两可的问题。这就是当写下
$$a[1]
时,解析器需要知道是想要
$a[1]
作为一个变量呢,还是想要
$$a
作为一个变量并取出该变量中索引为 [1]
的值。解决此问题的语法是,对第一种情况用
${$a[1]},对第二种情况用
${$a}[1]。
| 警告 |
注意,在 PHP 的函数和类的方法中,超全局变量不能用作可变变量。 |
当一个表单体交给 PHP 脚本时,表单中的信息会自动在脚本中可用。有很多方法访问此信息,例如:
根据特定的设置和个人的喜好,有很多种方法访问 HTML 表单中的数据。例如:
例 12-10. 从一个简单的 POST HTML 表单访问数据
|
使用 GET 表单也类似,只不过要用适当的 GET 预定义变量。GET
也适用于
QUERY_STRING(URL 中在“?”之后的信息)。因此,举例说,http://www.example.com/test.php?id=3
包含有可用 $_GET['id']
访问的 GET 数据。参见
$_REQUEST 和
import_request_variables()。
注意: 超全局变量和
$_POST以及$_GET一样,自 PHP 4.1.0 起可用。
如上所示,在 PHP 4.2.0 之前 register_globals 的默认值是 on。在 PHP 3 中其值总是 on。PHP 社区鼓励大家不要依赖此指令,建议在编码时假定其为 off。
注意: magic_quotes_gpc 配置指令影响到 Get,Post 和 Cookie 的值。如果打开,值 (It's "PHP!") 会自动转换成 (It\'s \"PHP!\")。数据库的插入就需要转义。参见 addslashes(),stripslashes() 和 magic_quotes_sybase。
PHP 也懂得表单变量上下文中的数组(参见相关常见问题)。例如可以将相关的变量编成组,或者用此特性从多选输入框中取得值。例如,将一个表单 POST 给自己并在提交时显示数据:
例 12-11. 更复杂的表单变量
|
在 PHP 3 中,变量使用中的数组仅限于一维数组。在 PHP 4 中,没有此种限制。
当提交表单时,可以用一幅图像代替标准的提交按钮,用类似这样的标记:
当用户点击到图像中的某处时,相应的表单会被传送到服务器,并加上两个变量 sub_x 和 sub_y。它们包含了用户点击图像的坐标。有经验的用户可能会注意到被浏览器发送的实际变量名包含的是一个点而不是下划线(即 sub.x 和 sub.y),但 PHP 自动将点转换成了下划线。
PHP 透明地支持 Netscape 规范定义中的
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,除非路径或者域不同。因此对于购物车程序可以保留一个计数器并一起传递,例如:
例 12-12. 一个 setcookie() 的示例
|
通常,PHP 不会改变传递给脚本中的变量名。然而应该注意到点(句号)不是 PHP 变量名中的合法字符。至于原因,看看:
<?php $varname.ext; /* 非法变量名 */ ?> |
$varname
的变量,后面跟着一个字符串连接运算符,后面跟着一个裸字符串(即没有加引号的字符串,且不匹配任何已知的健名或保留字)'ext'。很明显这不是想要的结果。
出于此原因,要注意 PHP 将会自动将变量名中的点替换成下划线。
因为 PHP 会判断变量类型并在需要时进行转换(通常情况下),因此在某一时刻给定的变量是何种类型并不明显。PHP 包括几个函数可以判断变量的类型,例如:gettype(),is_array(),is_float(),is_int(),is_object() 和 is_string()。参见类型一章。
常量是一个简单值的标识符(名字)。如同其名称所暗示的,在脚本执行期间该值不能改变(除了所谓的魔术常量,它们其实不是常量)。常量默认为大小写敏感。按照惯例常量标识符总是大写的。
常量名和其它任何 PHP 标签遵循同样的命名规则。合法的常量名以字母或下划线开始,后面跟着任何字母,数字或下划线。用正则表达式是这样表达的:[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*
例 13-1. 合法与非法的常量名
|
注意: 在这里,字母是 a-z,A-Z,以及从 127 到 255(0x7f-0xff)的 ASCII 字符。
和 superglobals 一样,常量的范围是全局的。不用管作用域就可以在脚本的任何地方访问常量。有关作用得更多信息请阅读手册中的变量范围。
可以用 define() 函数来定义常量。一个常量一旦被定义,就不能再改变或者取消定义。
常量只能包含标量数据(boolean,integer,float 和 string)。 不要定义 resource 常量。
可以简单的通过指定其名字来取得常量的值,不要在常量前面加上 $ 符号。如果常量名是动态的,也可以用函数 constant() 来读取常量的值。用 get_defined_constants() 可以获得所有已定义的常量列表。
注意: 常量和(全局)变量在不同的名字空间中。这意味着例如 TRUE 和
$TRUE是不同的。
如果使用了一个未定义的常量,PHP 假定想要的是该常量本身的名字,如同用字符串调用它一样(CONSTANT 对应 "CONSTANT")。此时将发出一个 E_NOTICE 级的错误。参见手册中为什么 $foo[bar] 是错误的(除非事先用 define() 将 bar 定义为一个常量)。如果只想检查是否定义了某常量,用 defined() 函数。
常量和变量不同:
常量前面没有美元符号($);
常量只能用 define() 函数定义,而不能通过赋值语句;
常量可以不用理会变量范围的规则而在任何地方定义和访问;
常量一旦定义就不能被重新定义或者取消定义;
常量的值只能是标量。
参见类常量。
PHP 向它运行的任何脚本提供了大量的预定义常量。不过很多常量都是由不同的扩展库定义的,只有在加载了这些扩展库时才会出现,或者动态加载后,或者在编译时已经包括进去了。
有五个魔术常量根据它们使用的位置而改变。例如 __LINE__ 的值就依赖于它在脚本中所处的行来决定。这些特殊的常量不区分大小写,如下:
表 13-1. 几个 PHP 的“魔术常量”
| 名称 | 说明 |
|---|---|
| __LINE__ | 文件中的当前行号。 |
| __FILE__ | 文件的完整路径和文件名。如果用在包含文件中,则返回包含文件名。自 PHP 4.0.2 起,__FILE__ 总是包含一个绝对路径,而在此之前的版本有时会包含一个相对路径。 |
| __FUNCTION__ | 函数名称(PHP 4.3.0 新加)。自 PHP 5 起本常量返回该函数被定义时的名字(区分大小写)。在 PHP 4 中该值总是小写字母的。 |
| __CLASS__ | 类的名称(PHP 4.3.0 新加)。自 PHP 5 起本常量返回该类被定义时的名字(区分大小写)。在 PHP 4 中该值总是小写字母的。 |
| __METHOD__ | 类的方法名(PHP 5.0.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 的表达式。如果一切运行正确,那这正是将要发生的正确结果。
稍微复杂的表达式例子就是函数。例如,考虑下面的函数:
假定已经熟悉了函数的概念(如果不是的话,请看一下函数的相关章节),那么键入 $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),等等。
还有一个表达式,如果没有在别的语言中看到过的话,可能看上去很奇怪,即三元条件运算符:
如果第一个子表达式的值是 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 表达式。
运算符是可以通过给出的一或多个值(用编程行话来说,表达式)来产生另一个值(因而整个结构成为一个表达式)的东西。所以可以认为函数或任何会返回一个值(例如 print)的结构是运算符,而那些没有返回值的(例如 echo)是别的东西。
有三种类型的运算符。第一种是一元运算符,只运算一个值,例如 !(取反运算符)或 ++(加一运算符)。第二种是有限二元运算符,PHP 支持的大多数运算符都是这种。列表见下节运算符优先级。
第三种是三元运算符:?:。它应该被用来根据一个表达式在另两个表达式中选择一个,而不是用来在两个语句或者程序路线中选择。把整个三元表达式放在扩号里是个很好的主意。
运算符优先级指定了两个表达式绑定得有多“紧密”。例如,表达式 1 + 5 * 3 的结果是 16 而不是 18 是因为乘号(“*”)的优先级比加号(“+”)高。必要时可以用括号来强制改变优先级。例如:(1 + 5) * 3 的值为 18。如果运算符优先级相同,则使用从左到右的左联顺序。
下表从高到低列出了运算符的优先级。同一行中的运算符具有相同优先级,此时它们的结合方向决定求值顺序。
表 15-1. 运算符优先级
| 结合方向 | 运算符 | 附加信息 |
|---|---|---|
| 非结合 | new | new |
| 左 | [ | array() |
| 非结合 | ++ -- | 递增/递减运算符 |
| 非结合 | ! ~ - (int) (float) (string) (array) (object) @ | 类型 |
| 左 | * / % | 算数运算符 |
| 左 | + - . | 算数运算符和字符串运算符 |
| 左 | << >> | 位运算符 |
| 非结合 | < <= > >= | 比较运算符 |
| 非结合 | == != === !== | 比较运算符 |
| 左 | & | 位运算符和引用 |
| 左 | ^ | 位运算符 |
| 左 | | | 位运算符 |
| 左 | && | 逻辑运算符 |
| 左 | || | 逻辑运算符 |
| 左 | ? : | 三元运算符 |
| 右 | = += -= *= /= .= %= &= |= ^= <<= >>= | 赋值运算符 |
| 左 | and | 逻辑运算符 |
| 左 | xor | 逻辑运算符 |
| 左 | or | 逻辑运算符 |
| 左 | , | 多处用到 |
左联表示表达式从左向右求值,右联相反。
注意: 尽管 ! 比 = 的优先级高,PHP 仍旧允许类似如下的表达式:if (!$a = foo()),在此例中 foo() 的输出被赋给了
$a。
还记得学校里学到的基本数学知识吗?就和它们一样。
表 15-2. 算术运算符
| 例子 | 名称 | 结果 |
|---|---|---|
| -$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 为负值时的结果也是负值。
参见手册中的数学函数。
基本的赋值运算符是“=”。一开始可能会以为它是“等于”,其实不是的。它实际上意味着把右边表达式的值赋给左边的运算数。
赋值运算表达式的值也就是所赋的值。也就是说,“$a = 3”的值是 3。这样就可以做一些小技巧:
在基本赋值运算符之外,还有适合于所有二元算术,数组集合和字符串运算符的“组合运算符”,这样可以在一个表达式中使用它的值并把表达式的结果赋给它,例如:
<?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 4 起支持引用赋值,用 $var = &$othervar; 语法,但在 PHP 3 中不可能这样做。引用赋值意味着两个变量都指向同一个数据,没有任何数据的拷贝。有关引用的更多信息见引用的说明。
位运算符允许对整型数中指定的位进行置位。如果左右参数都是字符串,则位运算符将操作字符的 ASCII 值。
<?php
echo 12 ^ 9; // 输出为 '5'
echo "12" ^ "9"; // 输出退格字符(ascii 8)
// ('1' (ascii 49)) ^ ('9' (ascii 57)) = #8
echo "hallo" ^ "hello"; // 输出 ascii 值 #0 #4 #0 #0 #0
// 'a' ^ 'e' = #4
?> |
表 15-3. 位运算符
| 例子 | 名称 | 结果 |
|---|---|---|
| $a & $b | And(按位与) | 将把 $a 和 $b 中都为 1 的位设为 1。 |
| $a | $b | Or(按位或) | 将把 $a 或者 $b 中为 1 的位设为 1。 |
| $a ^ $b | Xor(按位异或) | 将把 $a 和 $b 中不同的位设为 1。 |
| ~ $a | Not(按位非) | 将 $a 中为 0 的位设为 1,反之亦然。 |
| $a << $b | Shift left(左移) | 将 $a 中的位向左移动 $b 次(每一次移动都表示“乘以 2”)。 |
| $a >> $b | Shift right(右移) | 将 $a 中的位向右移动 $b 次(每一次移动都表示“除以 2”)。 |
| 警告 |
在 32 位系统上不要右移超过 32 位。不要在结果可能超过 32 位的情况下左移。 |
比较运算符,如同它们名称所暗示的,允许对两个值进行比较。还可以参考 PHP 类型比较表看不同类型相互比较的例子。
表 15-4. 比较运算符
| 例子 | 名称 | 结果 |
|---|---|---|
| $a == $b | 等于 | TRUE,如果 $a 等于 $b。 |
| $a === $b | 全等 | TRUE,如果 $a 等于 $b,并且它们的类型也相同。(PHP 4 引进) |
| $a != $b | 不等 | TRUE,如果 $a 不等于 $b。 |
| $a <> $b | 不等 | TRUE,如果 $a 不等于 $b。 |
| $a !== $b | 非全等 | TRUE,如果 $a 不等于 $b,或者它们的类型不同。(PHP 4 引进) |
| $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
switch ("a") {
case 0:
echo "0";
break;
case "a": // never reached because "a" is already matched with 0
echo "a";
break;
}
?> |
对于多种类型,比较运算符根据下表比较(按顺序)。
表 15-5. 比较多种类型
| 运算数 1 类型 | 运算数 1 类型 | 结果 |
|---|---|---|
| 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 中则数组无法比较,否则挨个值比较(见下例) |
| array | 任何其它类型 | array 总是更大 |
| object | 任何其它类型 | object 总是更大 |
例 15-2. 标准数组比较代码
|
参见 strcasecmp(),strcmp(),数组运算符和类型一章。
另一个条件运算符是“?:”(或三元)运算符 。
注意: 注意三元运算符是个语句,因此其求值不是变量,而是语句的结果。如果想通过引用返回一个变量这点就很重要。在一个通过引用返回的函数中语句 return $var == 42 ? $a : $b; 将不起作用,以后的 PHP 版本会为此发出一条警告。
PHP 支持一个错误控制运算符:@。当将其放置在一个 PHP 表达式之前,该表达式可能产生的任何错误信息都被忽略掉。
如果激活了 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.
?> |
注意: @ 运算符只对表达式有效。对新手来说一个简单的规则就是:如果能从某处得到值,就能在它前面加上 @ 运算符。例如,可以把它放在变量,函数和 include() 调用,常量,等等之前。不能把它放在函数或类的定义之前,也不能用于条件结构例如 if 和 foreach 等。
参见 error_reporting() 及手册中错误处理及日志函数的有关章节。
| 警告 |
目前的“@”错误控制运算符前缀甚至使导致脚本终止的严重错误的错误报告也失效。这意味着如果在某个不存在或类型错误的函数调用前用了“@”来抑制错误信息,那脚本会没有任何迹象显示原因而死在那里。 |
PHP 支持一个执行运算符:反引号(``)。注意这不是单引号!PHP 将尝试将反引号中的内容作为外壳命令来执行,并将其输出信息返回(例如,可以赋给一个变量而不是简单地丢弃到标准输出)。使用反引号运算符“`”的效果与函数 shell_exec() 相同。
注意: 反引号运算符在激活了安全模式或者关闭了 shell_exec() 时是无效的。
参见函数 popen()、proc_open() 及手册中程序执行函数和 PHP 的命令行模式的有关章节。
PHP 支持 C 风格的前/后递增与递减运算符。
注意: 递增/递减运算符不影响布尔值。递减 NULL 值也没有效果,但是递增 NULL 的结果是 1。
表 15-6. 递增/递减运算符
| 例子 | 名称 | 效果 |
|---|---|---|
| ++$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 中 'Z'+1 将得到 'AA',而在 C 中,'Z'+1 将得到 '['(ord('Z') == 90,ord('[') == 91)。注意字符变量只能递增,不能递减,并且只支持纯字母(a-z 和 A-Z)。
递增或递减布尔值没有效果。
表 15-7. 逻辑运算符
| 例子 | 名称 | 结果 |
|---|---|---|
| $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。 |
“与”和“或”有两种不同形式运算符的原因是它们运算的优先级不同(见运算符优先级)。
有两个字符串运算符。第一个是连接运算符(“.”),它返回其左右参数连接后的字符串。第二个是连接赋值运算符(“.=”),它将右边参数附加到左边的参数后。更多信息见赋值运算符。
表 15-8. 数组运算符
| 例子 | 名称 | 结果 |
|---|---|---|
| $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"
} |
数组中的单元如果具有相同的键名和值则比较时相等。
PHP 只有一个类型运算符:instanceof 用来测定一个给定的对象,它的父对象或它们所实现的接口是否来自指定的对象类。
instanceof 运算符是 PHP 5 引进的。在此之前用 is_a(),但是 is_a() 已经过时了,最好用 instanceof。
<?php
class A { }
class B { }
$thing = new A;
if ($thing instanceof A) {
echo 'A';
}
if ($thing instanceof B) {
echo 'B';
}
?> |
由于 $thing 是类型 A 的一个 object,而不是
B 的,只有和类型 A 相符合的程序块被运行:
A |
参见 get_class() 和 is_a()。
任何 PHP 脚本都是由一系列语句构成的。一条语句可以是一个赋值语句,一个函数调用,一个循环,一个条件语句或者甚至是一个什么也不做的语句(空语句)。语句通常以分号结束。此外,还可以用花括号将一组语句封装成一个语句组。语句组本身可以当作是一行语句。本章讲述了各种语句类型。
if 结构是很多语言包括 PHP 在内最重要的特性之一,它允许按照条件执行代码片段。PHP 的 if 结构和 C 语言相似:
如同在表达式一章中定义的,expr 按照布尔求值。如果 expr 的值为 TRUE,PHP 将执行 statement,如果值为 FALSE - 将忽略 statement。有关哪些值被视为 FALSE 的更多信息参见转换为布尔值一节。
如果 $a 大于 $b,则以下例子将显示
a is bigger than b:
经常需要按照条件执行不止一条语句,当然并不需要给每条语句都加上一个
if 子句。可以将这些语句放入语句组中。例如,如果
$a 大于 $b,以下代码将显示
a is bigger than b 并且将
$a 的值赋给 $b:
if 语句可以无限层地嵌套在其它 if 语句中,这给程序的不同部分的条件执行提供了充分的弹性。
经常需要在满足某个条件时执行一条语句,而在不满足该条件时执行其它语句,这正是
else 的功能。else 延伸了
if 语句,可以在 if
语句中的表达式的值为 FALSE 时执行语句。例如以下代码在
$a 大于 $b 时显示
a is bigger than b,反之则显示
a is NOT bigger than b:
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 时执行。
PHP 提供了一些流程控制的替代语法,包括 if,while,for,foreach 和 switch。替代语法的基本形式是把左花括号({)换成冒号(:),把右花括号(})分别换成 endif;,endwhile;,endfor;,endforeach; 以及 endswitch;。
在上面的例子中,HTML 内容“A is equal to 5”用替代语法嵌套在
if 语句中。该 HTML 的内容仅在
$a 等于 5 时显示。
替代语法同样可以用在 else 和 elseif 中。下面是一个包括 elseif 和 else 的 if 结构用替代语法格式写的例子:
while 循环是 PHP 中最简单的循环类型。它和 C 语言中的 while 表现得一样。while 语句的基本格式是:
while 语句的含意很简单,它告诉 PHP 只要 while 表达式的值为 TRUE 就重复执行嵌套中的循环语句。表达式的值在每次开始循环时检查,所以即使这个值在循环语句中改变了,语句也不会停止执行,直到本次循环结束。有时候如果 while 表达式的值一开始就是 FALSE,则循环语句一次都不会执行。
和 if 语句一样,可以在 while 循环中用花括号括起一个语句组,或者用替代语法:
下面两个例子完全一样,都显示数字 1 到 10:
do-while 和 while 循环非常相似,区别在于表达式的值是在每次循环结束时检查而不是开始时。和正规的 while 循环主要的区别是 do-while 的循环语句保证会执行一次(表达式的真值在每次循环结束后检查),然而在正规的 while 循环中就不一定了(表达式真值在循环开始时检查,如果一开始就为 FALSE 则整个循环立即终止)。
do-while 循环只有一种语法:
以上循环将正好运行一次,因为经过第一次循环后,当检查表达式的真值时,其值为 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);
?> |
如果还不能立刻理解也不用担心。即使不用此“特性”也照样可以写出强大的代码来。
for 循环是 PHP 中最复杂的循环结构。它的行为和 C 语言的相似。 for 循环的语法是:
第一个表达式(expr1)在循环开始前无条件求值一次。
expr2 在每次循环开始前求值。如果值为
TRUE,则继续循环,执行嵌套的循环语句。如果值为 FALSE,则终止循环。
expr3 在每次循环之后被求值(执行)。
每个表达式都可以为空。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; $i <= 10; echo $i, $i++);
?> |
当然,第一个例子看上去最正常(或者第四个),但用户可能会发现在 for 循环中用空的表达式在很多场合下会很方便。
PHP 也支持用冒号的 for 循环的替代语法。
PHP 4 引入了 foreach 结构,和 Perl 以及其他语言很像。这只是一种遍历数组简便方法。foreach 仅能用于数组,当试图将其用于其它数据类型或者一个未初始化的变量时会产生错误。有两种语法,第二种比较次要但却是第一种的有用的扩展。
foreach (array_expression as $value)
statement
foreach (array_expression as $key => $value)
statement |
第一种格式遍历给定的 array_expression 数组。每次循环中,当前单元的值被赋给 $value 并且数组内部的指针向前移一步(因此下一次循环中将会得到下一个单元)。
第二种格式做同样的事,只除了当前单元的键名也会在每次循环中被赋给变量 $key。
自PHP 5 起,还可能遍历对象。
注意: 当 foreach 开始执行时,数组内部的指针会自动指向第一个单元。这意味着不需要在 foreach 循环之前调用 reset()。
注意: 除非数组是被引用,foreach 所操作的是指定数组的一个拷贝,而不是该数组本身。因此数组指针不会被 each() 结构改变,对返回的数组单元的修改也不会影响原数组。不过原数组的内部指针的确在处理数组的过程中向前移动了。假定 foreach 循环运行到结束,原数组的内部指针将指向数组的结尾。
自 PHP 5 起,可以很容易地通过在 $value 之前加上 & 来修改数组的单元。此方法将以引用赋值而不是拷贝一个值。
此方法仅在被遍历的数组可以被引用时才可用(例如是个变量)。
注意: 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 key 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";
}
?> |
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";
}
/* Using the optional argument. */
$i = 0;
while (++$i) {
switch ($i) {
case 5:
echo "At 5<br />\n";
break 1; /* Exit only the switch. */
case 10:
echo "At 10; quitting<br />\n";
break 2; /* Exit the switch and the while. */
default:
break;
}
}
?> |
continue 在循环结构用用来跳过本次循环中剩余的代码并在条件求值为真时开始执行下一次循环。
注意: 注意在 PHP 中 switch 语句被认为是可以使用 continue 的一种循环结构。
continue 接受一个可选的数字参数来决定跳过几重循环到循环结尾。
<?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 |
因为 print() 调用的返回值是 int(1),看上去作为了上述可选的数字参数。
switch 语句和具有同样表达式的一系列的 IF 语句相似。很多场合下需要把同一个变量(或表达式)与很多不同的值比较,并根据它等于哪个值来执行不同的代码。这正是 switch 语句的用途。
注意: 注意和其它语言不同,continue 语句作用到 switch 上的作用类似于 break。如果在循环中有一个 switch 并希望 continue 到外层循环中的下一个轮回,用 continue 2。
下面两个例子使用两种不同方法实现同样的事,一个用一系列的 if 语句,另一个用 switch 语句:
为避免错误,理解 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 将执行所有的 print 语句!如果
$i 等于 1,PHP 将执行后面两条 print 语句。只有当
$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 都不匹配的情况,并且应该是最后一条 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 支持替代语法的流程控制。更多信息见流程控制的替代语法一节。
declare 结构用来设定一段代码的执行指令。declare 的语法和其它流程控制结构相似:
directive 部分允许设定 declare 代码段的行为。目前只认识一个指令:ticks(更多信息见下面 ticks 指令)。
declare 代码段中的 statement 部分将被执行――怎样执行以及执行中有什么副作用出现取决于 directive 中设定的指令。
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
?> |
Tick 是一个在 declare 代码段中解释器每执行
N 条低级语句就会发生的事件。N
的值是在 declare 中的 directive 部分用
ticks=N 来指定的。
在每个 tick 中出现的事件是由 register_tick_function() 来指定的。更多细节见下面的例子。注意每个 tick 中可以出现多个事件。
例 16-3. 评估一段 PHP 代码的执行时间
|
Ticks 很适合用来做调试,以及实现简单的多任务,后台 I/O 和很多其它任务。
如果在一个函数中调用 return() 语句,将立即结束此函数的执行并将它的参数作为函数的值返回。return() 也会终止 eval() 语句或者脚本文件的执行。
如果在全局范围中调用,则当前脚本文件中止运行。如果当前脚本文件是被 include() 的或者 require() 的,则控制交回调用文件。此外,如果当前脚本是被 include() 的,则 return() 的值会被当作 include() 调用的返回值。如果在主脚本文件中调用 return(),则脚本中止运行。如果当前脚本文件是在 php.ini 中的配置选项 auto_prepend_file 或者 auto_append_file 所指定的,则此脚本文件中止运行。
更多信息见返回值。
注意: 注意既然 return() 是语言结构而不是函数,仅在参数包含表达式时才需要用括号将其括起来。当返回一个变量时通常不用括号,也建议不要用,这样可以降低 PHP 的负担。
注意: 当用引用返回值时永远不要使用括号,这样行不通。只能通过引用返回变量,而不是语句的结果。如果使用 return ($a); 时其实不是返回一个变量,而是表达式 ($a) 的值(当然,此时该值也正是
$a的值)。
require() 语句包含并运行指定文件。
require() 语句包含并运行指定文件。有关包括如何工作的详细信息见 include() 的文档。
require() 和 include() 除了怎样处理失败之外在各方面都完全一样。include() 产生一个警告而 require() 则导致一个致命错误。换句话说,如果想在丢失文件时停止处理页面,那就别犹豫了,用 require() 吧。include() 就不是这样,脚本会继续运行。同时也要确认设置了合适的include_path。
例 16-4. 基本的 require() 例子
|
更多例子参见 include() 文档。
注意: 在 PHP 4.0.2 之前适用以下规则:require() 总是会尝试读取目标文件,即使它所在的行根本就不会执行。条件语句不会影响 require()。不过如果 require() 所在的行没有执行,则目标文件中的代码也不会执行。同样,循环结构也不影响 require() 的行为。尽管目标文件中包含的代码仍然是循环的主体,但 require() 本身只会运行一次。
注意: 由于这是一个语言结构而非函数,因此它无法被变量函数调用。
| 警告 |
Windows 版本的 PHP 在 4.3.0 版之前不支持本函数的远程文件访问,即使 allow_url_fopen 选项已被激活。 |
参见 include(),require_once(),include_once(),get_included_files(),eval(),file(),readfile(),virtual() 和 include_path。
include() 语句包含并运行指定文件。
以下文档也适用于 require()。这两种结构除了在如何处理失败之外完全一样。include() 产生一个警告而 require() 则导致一个致命错误。换句话说,如果想在遇到丢失文件时停止处理页面就用 require()。include() 就不是这样,脚本会继续运行。同时也要确认设置了合适的 include_path。注意在 PHP 4.3.5 之前,包含文件中的语法错误不会导致程序停止,但从此版本之后会。
寻找包含文件的顺序先是在当前工作目录的相对的 include_path 下寻找,然后是当前运行脚本所在目录相对的 include_path 下寻找。例如 include_path 是 .,当前工作目录是 /www/,脚本中要 include 一个 include/a.php 并且在该文件中有一句 include "b.php",则寻找 b.php 的顺序先是 /www/,然后是 /www/include/。如果文件名以 ./ 或者 ../ 开始,则只在当前工作目录相对的 include_path 下寻找。
当一个文件被包含时,其中所包含的代码继承了 include 所在行的变量范围。从该处开始,调用文件在该行处可用的任何变量在被调用的文件中也都可用。不过所有在包含文件中定义的函数和类都具有全局作用域。
例 16-5. 基本的 include() 例子
|
如果 include 出现于调用文件中的一个函数里,则被调用的文件中所包含的所有代码将表现得如同它们是在该函数内部定义的一样。所以它将遵循该函数的变量范围。
例 16-6. 函数中的包含
|
当一个文件被包含时,语法解析器在目标文件的开头脱离 PHP 模式并进入 HTML 模式,到文件结尾处恢复。由于此原因,目标文件中应被当作 PHP 代码执行的任何代码都必须被包括在有效的 PHP 起始和结束标记之中。
如果“URL fopen wrappers”在 PHP 中被激活(默认配置),可以用 URL(通过 HTTP 或者其它支持的封装协议――所支持的协议见附录 N)而不是本地文件来指定要被包含的文件。如果目标服务器将目标文件作为 PHP 代码解释,则可以用适用于 HTTP GET 的 URL 请求字符串来向被包括的文件传递变量。严格的说这和包含一个文件并继承父文件的变量空间并不是一回事;该脚本文件实际上已经在远程服务器上运行了,而本地脚本则包括了其结果。
| 警告 |
Windows 版本的 PHP 在 4.3.0 版之前不支持本函数的远程文件访问,即使 allow_url_fopen 选项已被激活。 |
例 16-7. 通过 HTTP 进行的 include()
|
| 安全警告 |
远程文件可能会经远程服务器处理(根据文件后缀以及远程服务器是否在运行 PHP 而定),但必须产生出一个合法的 PHP 脚本,因为其将被本地服务器处理。如果来自远程服务器的文件应该在远端运行而只输出结果,那用 readfile() 函数更好。另外还要格外小心以确保远程的脚本产生出合法并且是所需的代码。 |
相关信息参见使用远程文件,fopen() 和 file()。
因为 include() 和 require() 是特殊的语言结构,在条件语句中使用必须将其放在语句组中(花括号中)。
处理返回值:可以在被包括的文件中使用 return() 语句来终止该文件中程序的执行并返回调用它的脚本。同样也可以从被包含的文件中返回值。可以像普通函数一样获得 include 调用的返回值。不过这在包含远程文件时却不行,除非远程文件的输出具有合法的 PHP 开始和结束标记(如同任何本地文件一样)。可以在标记内定义所需的变量,该变量在文件被包含的位置之后就可用了。
因为 include() 是一个特殊的语言结构,其参数不需要括号。在比较其返回值时要注意。
注意: 在 PHP 3 中,除非是在函数中调用否则被包含的文件中不能出现 return。在此情况下 return() 作用于该函数而不是整个文件。
$bar 的值为 1 是因为 include 成功运行了。注意以上例子中的区别。第一个在被包含的文件中用了 return() 而另一个没有。如果文件不能被包含,则返回 FALSE 并发出一个 E_WARNING 警告。
如果在包含文件中定义有函数,这些函数可以独立于是否在 return() 之前还是之后在主文件中使用。如果文件被包含两次,PHP 5 发出致命错误因为函数已经被定义,但是 PHP 在 return() 之后不会抱怨函数已定义。推荐使用 include_once() 而不是检查文件是否已包含并在包含文件中有条件返回。
另一个将 PHP 文件“包含”到一个变量中的方法是用输出控制函数结合 include() 来捕获其输出,例如:
要在脚本中自动包含文件,参见 php.ini 中的 auto_prepend_file 和 auto_append_file 配置选项。
注意: 由于这是一个语言结构而非函数,因此它无法被变量函数调用。
参见 require(),require_once(),include_once(),get_included_files(),readfile(),virtual() 和 include_path。
require_once() 语句在脚本执行期间包含并运行指定文件。此行为和 require() 语句类似,唯一区别是如果该文件中的代码已经被包含了,则不会再次包含。有关此语句怎样工作参见 require() 的文档。
require_once() 应该用于在脚本执行期间同一个文件有可能被包含超过一次的情况下,想确保它只被包含一次以避免函数重定义,变量重新赋值等问题。
使用 require_once() 和 include_once() 的例子见最新的 PHP 源程序发行包中的 PEAR 代码。
返回值和 include() 相同。如果文件已被包含,本函数返回 TRUE。
注意: require_once() 是 PHP 4.0.1pl2 中新加入的。
注意: 要注意 require_once() 和 include_once() 在大小写不敏感的操作系统中(例如 Windows)的行为可能不是所期望的。
此行为在 PHP 5 中改了,路径先被规格化,因此 C:\PROGRA~1\A.php 和 C:\Program Files\a.php 的实现一样,文件只会被包含一次。
例 16-12. require_once() 在 Windows 下不区分大小写
<?php require_once("a.php"); // this will include a.php require_once("A.php"); // this will include a.php again on Windows! ?>
| 警告 |
Windows 版本的 PHP 在 4.3.0 版之前不支持本函数的远程文件访问,即使 allow_url_fopen 选项已被激活。 |
参见 require(),include(),include_once(),get_required_files(),get_included_files(),readfile() 和 virtual()。
The include_once() 语句在脚本执行期间包含并运行指定文件。此行为和 include() 语句类似,唯一区别是如果该文件中的代码已经被包含了,则不会再次包含。如同此语句名字暗示的那样,只会包含一次。
include_once() 应该用于在脚本执行期间同一个文件有可能被包含超过一次的情况下,想确保它只被包含一次以避免函数重定义,变量重新赋值等问题。
使用 require_once() 和 include_once() 的更多例子见最新的 PHP 源程序发行包中的 PEAR 代码。
返回值和 include() 相同。如果文件已被包含,本函数返回 TRUE。
注意: include_once() 是 PHP 4.0.1pl2 中新加入的。
注意: 要注意 include_once() 和 require_once() 在大小写不敏感的操作系统中(例如 Windows)的行为可能不是所期望的。
此行为在 PHP 5 中改了,路径先被规格化,因此 C:\PROGRA~1\A.php 和 C:\Program Files\a.php 的实现一样,文件只会被包含一次。
例 16-13. include_once() 在 Windows 下不区分大小写
<?php include_once("a.php"); // this will include a.php include_once("A.php"); // this will include a.php again on Windows! (PHP 4 only) ?>
| 警告 |
Windows 版本的 PHP 在 4.3.0 版之前不支持本函数的远程文件访问,即使 allow_url_fopen 选项已被激活。 |
参见 include(),require(),require_once(),get_required_files(),get_included_files(),readfile() 和 virtual()。
一个函数可由以下的语法来定义:
任何有效的 PHP 代码都有可能出现在函数内部,甚至包括其它函数和类定义。
函数名和 PHP 中的其它标签命名规则相同。有效的函数名以字母或下划线打头,后面跟字母,数字或下划线。可以用正则表达式表示为:[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*。
在 PHP 3 中,函数必须在被调用之前定义。而 PHP 4 则不再有这样的条件。除非函数如以下两个范例中有条件的定义。
如果一个函数以以下两个范例的方式有条件的定义,其定义必须在调用之前完成。
例 17-2. 有条件的函数
|
PHP 中的所有函数和类都具有全局域,可以在内部定义外部调用,反之亦然。
PHP 不支持函数重载,也不可能取消定义或者重定义已声明的函数。
注意: 函数名是非大小写敏感的,不过在调用函数的时候,通常使用其在定义时相同的形式。
PHP 3 虽然支持默认参数(更多信息请参照默认参数的值),但是却不支持可变的参数个数。PHP 4 支持:见可变长度的参数列表和涉及到的相关函数 func_num_args(), func_get_arg(),以及 func_get_args() 以获取更多的信息。
在 PHP 中可以调用递归函数。但是要避免递归函数/方法调用超过 100-200 层,因为可能会破坏堆栈从而使当前脚本终止。
通过参数列表可以传递信息到函数,即以逗号作为分隔符的表达式列表。
PHP 支持按值传递参数(默认),通过引用传递以及默认参数。可变长度参数列表仅在 PHP 4 和后续版本中支持;更多信息请参照可变长度参数列表和涉及到的相关函数 func_num_args(),func_get_arg() 以及 func_get_args()。PHP 3 中通过传递一个数组参数可以达到类似的效果:
缺省情况下,函数参数通过值传递(因而即使在函数内部改变参数的值,它并不会改变函数外部的值)。如果希望允许函数修改它的参数值,必须通过引用传递参数。
如果想要函数的一个参数总是通过引用传递,可以在函数定义中该参数的前面预先加上符号 &:
函数可以定义 C++ 风格的标量参数默认值,如下:
上面代码段的输出是:
Making a cup of cappuccino. Making a cup of espresso. |
PHP 还允许使用数组和特殊类型 NULL 作为默认参数,例如:
例 17-8. 使用非标量类型作为默认参数
|
默认值必须是常量表达式,不是(例如)变量,类成员,或者函数调用。
请注意当使用默认参数时,任何默认参数必须放在任何非默认参数的右侧;否则,可能函数将不会按照预期的情况工作。考虑下面的代码片断:
上述例子的输出是:
Warning: Missing argument 2 in call to makeyogurt() in /usr/local/etc/httpd/htdocs/php3test/functest.html on line 41 Making a bowl of raspberry . |
现在,比较上面的例子和这个例子:
这个例子的输出是:
Making a bowl of acidophilus raspberry. |
注意: 自 PHP 5 起,默认值可以通过引用传递。
PHP 4 及更高版本已经在用户自定义函数中支持可变长度参数列表。这个真的很简单,用 func_num_args(),func_get_arg(),和 func_get_args() 函数。
无需特别的语法,参数列表仍然能够被明确无误的传递给函数并且正常运转。
值通过使用可选的返回语句返回。任何类型都可以返回,其中包括列表和对象。这导致函数立即结束它的运行,并且将控制权传递回它被调用的行。更多信息见 return()。
例 17-11. return() 的用法
|
函数不能返回多个值,但为了获得简单的结果,可以返回一个列表。
从函数返回一个引用,必须在函数声明和指派返回值给一个变量时都使用引用操作符 & :
有关引用的更多信息, 请查看引用的解释。
PHP 支持变量函数的概念。这意味着如果一个变量名后有圆括号,PHP 将寻找与变量的值同名的函数,并且将尝试执行它。除了别的事情以外,这个可以被用于实现回调函数,函数表等等。
变量函数不能用于语言结构,例如 echo(),print(),unset(),isset(),empty(),include(),require() 以及类似的语句。需要使用自己的外壳函数来将这些结构用作变量函数。
例 17-14. 变量函数示例
|
还可以利用变量函数的特性来调用一个对象的方法。
PHP 有很多标准的函数和结构。还有一些函数需要和特定地 PHP 扩展模块一起编译,否则在使用它们的时候就会得到一个致命的“未定义函数”错误。例如,要使用图像函数比如 imagecreatetruecolor(),需要在编译 PHP 的时候加上 GD 的支持。或者,要使用 mysql_connect() 函数,就需要在编译 PHP 的时候加上 MySQL 支持。有很多核心函数已包含在每个版本的 PHP 中如字符串和变量函数。调用 phpinfo() 或者 get_loaded_extensions() 可以得知 PHP 加载了那些扩展库。同时还应该注意,很多扩展库默认就是有效的。PHP 手册按照不同的扩展库组织了它们的文档。请参阅配置,安装以及各自的扩展库章节以获取有关如何设置 PHP 的信息。
手册中如何阅读函数原型讲解了如何阅读和理解一个函数的原型。确认一个函数将返回什么,或者函数是否直接作用于传递的参数是很重要的。例如,str_replace() 函数将返回修改过的字符串,而 usort() 却直接作用于传递的参数变量本身。手册中,每一个函数的页面中都有关于函数参数、行为改变、成功与否的返回值以及使用条件等信息。了解这些重要的(常常是细微的)差别是编写正确的 PHP 代码的关键。
类是变量与作用于这些变量的函数的集合。使用下面的语法定义一个类:
<?php
class Cart {
var $items; // 购物车中的物品
// 将 $num 个 $artnr 物品加入购物车
function add_item($artnr, $num) {
$this->items[$artnr] += $num;
}
// 将 $num 个 $artnr 物品从购物车中取出
function remove_item($artnr, $num) {
if ($this->items[$artnr] > $num) {
$this->items[$artnr] -= $num;
return true;
} elseif ($this->items[$artnr] == $num) {
unset($this->items[$artnr]);
return true;
} else {
return false;
}
}
}
?> |
上面的例子定义了一个 Cart 类,这个类由购物车中的商品构成的数组和两个用于从购物车中添加和删除商品的函数组成。
| 警告 |
不能将一个类的定义分割到多个文件中。也不能将一个类的定义分割到多个 PHP 块中,除非该分割是在一个方法声明内部。以下用法将不起作用:
但是以下用法是可以的:
|
以下警告仅用于 PHP 4。
| 小心 |
名称 stdClass 已经被 Zend 使用并保留。不能在 PHP 代码中定义名为 stdClass 的类。 |
| 小心 |
函数名 __sleep 和 __wakeup 在 PHP 类中是魔术函数。除非想要与之联系的魔术功能,否则在任何类中都不能以此命名函数。 |
| 小心 |
PHP 将所有以 __ 开头的函数名保留为魔术函数。除非想要使用一些见于文档中的魔术功能,否则建议不要在 PHP 中将函数名以 __ 开头。 |
在 PHP 4 中,var 变量的值只能初始化为常量。用非常量值初始化变量,需要一个初始化函数,该函数在对象被创建时自动被调用。这样一个函数被称之为构造函数(见下面)。
<?php
/* PHP 4 中不能这样用 */
class Cart {
var $todays_date = date("Y-m-d");
var $name = $firstname;
var $owner = 'Fred ' . 'Jones';
/* 不过包含有常量的数组可以 */
var $items = array("VCR", "TV");
}
/* 应该这样进行 */
class Cart {
var $todays_date;
var $name;
var $owner;
var $items = array("VCR", "TV");
function Cart() {
$this->todays_date = date("Y-m-d");
$this->name = $GLOBALS['firstname'];
/* etc. . . */
}
}
?> |
类也是一种类型,就是说,它们是实际变量的蓝图。必须用 new 运算符来创建相应类型的变量。
<?php
$cart = new Cart;
$cart->add_item("10", 1);
$another_cart = new Cart;
$another_cart->add_item("0815", 3);
?> |
上述代码创建了两个 Cart 类的对象 $cart 和
$another_cart,对象 $cart 的方法 add_item()
被调用时,添加了 1 件 10 号商品。对于对象 $another_cart,3
件 0815 号商品被添加到购物车中。
$cart 和 $another_cart 都有方法
add_item(),remove_item() 和一个 items
变量。它们都是明显的函数和变量。可以把它们当作文件系统中的某些类似目录的东西来考虑。在文件系统中,可以拥有两个不同的
README.TXT 文件,只要不在相同的目录中。正如从为了根目录访问每个文件需要输入该文件的完整的路径名一样,必须指定需要调用的函数的完整名称:在
PHP 术语中,根目录将是全局名字空间,路径名符号将是
->。因而,名称 $cart->items
和 $another_cart->items
命名了两个不同的变量。注意变量名为 $cart->items,不是
$cart->$items,那是因为在 PHP 中一个变量名只有一个单独的美元符号。
<?php
// 正确,只有一个 $
$cart->items = array("10" => 1);
// 不正确,因为 $cart->$items 变成了 $cart->""
$cart->$items = array("10" => 1);
// 正确,但可能不是想要的结果:
// $cart->$myvar 变成了 $cart->items
$myvar = 'items';
$cart->$myvar = array("10" => 1);
?> |
在定义类的时候,无法得知将使什么名字的对象来访问:在编写 Cart
类时,并不知道之后对象的名称将会命名为 $cart
或者 $another_cart。因而你不能在类中使用
$cart->items。然而为了类定义的内部访问自身的函数和变量,可以使用伪变量
$this
来达到这个目的。$this 变量可以理解为“我自己的”或者“当前对象”。因而
'$this->items[$artnr] += $num' 可以理解为“我自己的物品数组的
$artnr 计数器加
$num”或者“在当前对象的物品数组的
$artnr 计数器加 $num”。
注意: 伪变量
$this通常未定义,如果其所在的方法是被静态调用的话。但这不是个严格规定:如果一个方法被从另一个对象内静态调用的话,则$this会被定义。此时$this的值是那个发出调用的对象。用下例演示:
<?php class A { function foo() { if (isset($this)) { echo '$this is defined ('; echo get_class($this); echo ")\n"; } else { echo "\$this is not defined.\n"; } } } class B { function bar() { A::foo(); } } $a = new A(); $a->foo(); A::foo(); $b = new B(); $b->bar(); B::bar(); ?>上例将输出:
$this is defined (a) $this is not defined. $this is defined (b) $this is not defined.
注意: 有一些不错的函数用来处理类和对象。应该关注一下类/对象函数。
通常需要这样一些类,这些类与其它现有的类拥有相同变量和函数。实际上,定义一个通用类用于所有的项目,并且不断丰富这个类以适应每个具体项目将是一个不错的练习。为了使这一点变得更加容易,类可以从其它的类中扩展出来。扩展或派生出来的类拥有其基类(这称为“继承”,只不过没人死)的所有变量和函数,并包含所有派生类中定义的部分。类中的元素不可能减少,就是说,不可以注销任何存在的函数或者变量。一个扩充类总是依赖一个单独的基类,也就是说,不支持多继承。使用关键字“extends”来扩展一个类。
<?php
class Named_Cart extends Cart {
var $owner;
function set_owner ($name) {
$this->owner = $name;
}
}
?> |
上述示例定义了名为 Named_Cart 的类,该类拥有 Cart
类的所有变量和函数,加上附加的变量 $owner 和一个附加函数
set_owner()。现在,以正常的方式创建了一个有名字的购物车,并且可以设置并取得该购物车的主人。而正常的购物车类的函数依旧可以在有名字的购物车类中使用:
<?php
$ncart = new Named_Cart; // 新建一个有名字的购物车
$ncart->set_owner("kris"); // 给该购物车命名
print $ncart->owner; // 输出该购物车主人的名字
$ncart->add_item("10", 1); // (从购物车类中继承来的功能)
?> |
这个也可以叫做“父-子”关系。创建一个类,父类,并使用 extends 来创建一个基于父类的新类:子类。甚至可以使用这个新的子类来创建另外一个基于这个子类的类。
注意: 类只有在定义后才可以使用!如果需要类 Named_Cart 继承类 Cart,必须首先定义 Cart 类。如果需要创建另一个基于 Named_Cart 类的 Yellow_named_cart 类,必须首先定义 Named_Cart 类。简捷的说:类定义的顺序是非常重要的。
构造函数是类中的一个特殊函数,当使用 new 操作符创建一个类的实例时,构造函数将会自动调用。当函数与类同名时,这个函数将成为构造函数。如果一个类没有构造函数,则调用基类的构造函数,如果有的话。
上文定义了一个 Auto_Cart 类,即 Cart 类加上一个构造函数,当每次使用“new”创建一个新的 Auto_Cart 类实例时,构造函数将自动调用并将一件商品的数目初始化为“10”。构造函数可以使用参数,而且这些参数可以是可选的,它们可以使构造函数更加有用。为了依然可以不带参数地使用类,所有构造函数的参数应该提供默认值,使其可选。
<?php
class Constructor_Cart extends Cart {
function Constructor_Cart($item = "10", $num = 1) {
$this->add_item ($item, $num);
}
}
// 买些同样的无聊老货
$default_cart = new Constructor_Cart;
// 买些实在货...
$different_cart = new Constructor_Cart("20", 17);
?> |
也可以使用 @ 操作符来抑制发生在构造函数中的错误。例如 @new。
<?php
class A
{
function A()
{
echo "I am the constructor of A.<br>\n";
}
function B()
{
echo "I am a regular function named B in class A.<br>\n";
echo "I am not a constructor in A.<br>\n";
}
}
class B extends A
{
function C()
{
echo "I am a regular function.<br>\n";
}
}
// 调用 B() 作为构造函数
$b = new B;
?> |
类 A 中的函数 B() 将立即成为类 B 中的构造函数,虽然并不是有意如此。PHP 4 并不关心函数是否在类 B 中定义的,或者是否被继承来的。
| 小心 |
|