Zend API:深入 PHP 内核 (-)译序及进度目录(已翻译完毕)
译序:
网上关于 PHP 的资料多如牛毛,关于其核心 Zend Engine 的却少之又少。PHP 中文手册出现已 N 年,但 Zend API 的翻译却仍然不见动静,小弟自觉对 Zend Engine 略有小窥,并且翻译也有助于强迫自己对文章的进一步理解,于是尝试翻译此章,英文不好,恭请方家指点校核。转载请注明来自抚琴居(译者主页):/
PHP 中文手册《Zend API:深入 PHP 内核》一章当前翻译进度(已翻译完毕):
1.摘要
2.概述
3.可扩展性
4.源码布局
5.自动构建系统
6.开始创建扩展
7.使用扩展
8.故障处理
9.关于模块代码的讨论
10.接收参数
11.创建变量
12.使用拷贝构造函数复制变量内容
13.返回函数值
14.信息输出
15.启动函数与关闭函数
16.调用用户函数
17.支持初始化文件(php.ini)
18.何去何从
19.参考:关于配置文件的一些宏
20.API 宏
Zend API:深入 PHP 内核 (二)摘要
摘要
知者不言,言者不知。
――老子《道德经》五十六章
有时候,单纯依靠 PHP “本身”是不行的。尽管普通用户很少遇到这种情况,但一些专业性的应用则经常需要将 PHP 的性能发挥到极致(这里的性能是指速度或功能)。由于受到 PHP 语言本身的限制,同时还可能不得不把庞大的库文件包含到每个脚本当中。因此,某些新功能并不是总能被顺利实现,所以我们必须另外寻一些方法来克服 PHP 的这些缺点。
了解到了这一点,我们就应该接触一下 PHP 的心脏并探究一下它的内核-可以编译成 PHP 并让之工作的 C 代码-
的时候了。
Zend API:深入 PHP 内核 (三)概述
“扩展 PHP”说起来容易做起来难。PHP 现在已经发展成了一个具有数兆字节源代码的非常成熟的系统。要想深入这样的一个系统,有很多东西需要学习和考虑。在写这一章节的时候,我们最终决定采用“边学边做”的方式。这也许并不是最科学和专业的方式,但却应该是最有趣和最有效的一种方式。在下面的小节里,你首先会非常快速的学习到如何写一个虽然很基础但却能立即运行的扩展,然后将会学习到有关 Zend API 的高级功能。另外一个选择就是将其作为一个整体,一次性的讲述所有的这些操作、设计、技巧和诀窍等,并且可以让我们在实际动手前就可以得到一副完整的愿景。这看起来似乎是一个更好的方法,也没有死角,但它却枯燥无味、费时费力,很容易让人感到气馁。这就是我们为什么要采用非常直接的讲法的原因。
注意,尽管这一章会尽可能多讲述一些关于 PHP 内部工作机制的知识,但要想真的给出一份在任何时间任何情况下的PHP 扩展指南,那简直是不可能的。PHP 是如此庞大和复杂,以致于只有你亲自动手实践一下才有可能真正理解它的内部工作机制,因此我们强烈推荐你随时参考它的源代码来进行工作。
Zend 是什么? PHP 又是什么?
Zend 指的是语言引擎,PHP 指的是我们从外面看到的一套完整的系统。这听起来有点糊涂,但其实并不复杂(见图3-1 PHP 内部结构图)。为了实现一个 WEB 脚本的解释器,你需要完成以下三个部分的工作:
1.解释器部分:负责对输入代码的分析、翻译和执行;
2.功能性部分:负责具体实现语言的各种功能(比如它的函数等等);
3.接口部分:负责同 WEB 服务器的会话等功能。
Zend 包括了第一部分的全部和第二部分的局部,PHP 包括了第二部分的局部和第三部分的全部。他们合起来称之为PHP 包。Zend 构成了语言的核心,同时也包含了一些最基本的 PHP 预定义函数的实现。PHP 则包含了所有创造出语言本身各种显著特性的模块。
图3-1 PHP 内部结构图
下面将要讨论PHP 允许在哪里扩展以及如何扩展。
Zend API:深入 PHP 内核 (四)可扩展性
正如上图(图3-1 PHP 内部结构图)所示,PHP 主要以三种方式来进行扩展:外部模块,内建模块和 Zend 引擎。下面我们将分别讨论这些方式:
外部模块
外部模块可以在脚本运行时使用 dl() 函数载入。这个函数从磁盘载入一个共享对象并将它的功能与调用该函数的脚本进行绑定并使之生效。脚本终止后,这个外部模块将在内存中被丢弃。这种方式有利有弊,如下表所示:
优点缺点
外部模块不需要重新对 PHP 进
共享对象在每次脚本调用时都需要对其进行加载,速度较慢。
行编译。
PHP通过“外包”方式来让自身的
附加的外部模块文件会让磁盘变得比较散乱。
体积保持很小。
每个想使用该模块功能的脚本都必须使用dl() 函数手动加载,或者
在 php.ini 文件当中添加一些扩展标签(这并不总是一个恰当的解
决方案)。
综上所述,外部模块非常适合开发第三方产品,较少使用的附加的小功能或者仅仅是调试等这些用途。为了迅速开发一些附加功能,外部模块是最佳方式。但对于一些经常使用的、实现较大的,代码较为复杂的应用,那就有些得不偿失了。
第三方可能会考虑在 php.ini 文件中使用扩展标签来创建一个新的外部模块。这些外部模块完全同主PHP 包分离,这一点非常适合应用于一些商业环境。商业性的发行商可以仅发送这些外部模块而不必再额外创建那些并不允许绑定这些商业模块的PHP 二进制代码。
内建模块
内建模块被直接编译进 PHP 并存在于每一个 PHP 处理请求当中。它们的功能在脚本开始运行时立即生效。和外部模块一样,内建模块也有一下利弊:
优点缺点
无需专门手动载入,功能即时生效。修改内建模块时需要重新编译PHP。
无需额外的磁盘文件,所有功能均内置在 PHP 二
PHP 二进制文件会变大并且会消耗更多的内存。
进制代码当中。
Zend 引擎
当然,你也能直接在 Zend 引擎里面进行扩展。如果你需要在语言特性方面做些改动或者是需要在语言核心内置一些特别的功能,那么这就是一种很好的方式。但一般情况下应该尽力避免对 Zend 引擎的修改。这里面的改动会导致和其他代码的不兼容,而且几乎没有人会适应打过特殊补丁的 Zend 引擎。况且这些改动与主 PHP 源代码是不可分割的,因此就有可能在下一次的官方的源代码更新中被覆盖掉。因此,这种方式通常被认为是“不良的习惯”。由于使用极其稀少,本章将不再对此进行赘述。
Zend API:深入 PHP 内核 (五)源码布局
在我们开始讨论具体编码这个话题前,你应该让自己熟悉一下 PHP 的源代码树以便可以迅速地对各个源文件进行定位。这也是编写和调试 PHP 扩展所必须具备的一种能力。
下表列出了一些主要目录的内容:
目录内容
php-src 包含了PHP主源文件和主头文件;在这里你可以到所有的 PHP API 定义、宏等内容。(重要). 其他的一些东西你也可以在这里到。
php-src/ext 这里是存放动态和内建模块的仓库;默认情况下,这些就是被集成于主源码树中的“官方” PHP 模块。自 PHP 4.0开始,这些PHP标准扩展都可以编译为动态可载入的模
块。(至少这些是可以的)。
php-src/main 这个目录包含主要的 PHP 宏和定义。(重要)
php-src/pear 这个目录就是“PHP 扩展与应用仓库”的目录。包含了PEAR 的核心文件。
php-src/sapi 包含了不同服务器抽象层的代码。
TSRM Zend 和 PHP的“线程安全资源管理器” (TSRM) 目录。
ZendEngine2 包含了Zend 引擎文件;在这里你可以到所有的 Zend API 定义与宏等。(重要) 当然,讨论 PHP 包里面全部每一个文件无疑是超出了本章的范围,但你还是应该仔细看一下下面的几个文件
•php-src/main/php.h, 位于PHP 主目录。这个文件包含了绝大部分 PHP 宏及 API 定义。
•php-src/Zend/zend.h, 位于 Zend 主目录。这个文件包含了绝大部分 Zend 宏及 API 定义。
•php-src/Zend/zend_API.h, 也位于 Zend 主目录,包含了Zend API 的定义。
除此之外,你也应该注意一下这些文件所包含的一些文件。举例来说,哪些文件与 Zend 执行器有关,哪些文件又为PHP 初始化工作提供了支持等等。在阅读完这些文件之后,你还可以花点时间再围绕PHP包来看一些文件,了解一下这些文件和模块之间的依赖性――它们之间是如何依赖于别的文件又是如何为其他文件提供支持的。同时这也可以帮助你适应一下 PHP 创作者们代码的风格。要想扩展 PHP,你应该尽快适应这种风格。
扩展规范
Zend 是用一些特定的规范构建的。为了避免破坏这些规范,你应该遵循以下的几个规则:宏
几乎对于每一项重要的任务,Zend 都预先提供了极为方便的宏。在下面章节的图表里将会描述到大部分基本函数、结构和宏。这些宏定义大多可以在 Zend.h 和 Zend_API.h 中到。我们建议您在学习完本节之后仔细看一下这些文件。(当然你也可以现在就阅读这些文件,但你可能不会留下太多的印象。)
内存管理
资源管理仍然是一个极为关键的问题,尤其是对服务器软件而言。资源里最具宝贵的则非内存莫属了,内存管理也必须极端小心。内存管理在 Zend 中已经被部分抽象,而且你也应该坚持使用这些抽象,原因显而易见:由于得以抽象,Zend 就可以完全控制内存的分配。Zend 可以确定一块内存是否在使用,也可以自动释放未使用和失去引用的内存块,因此就可以避免内存泄漏。下表列出了一些常用函数:
函数描述emalloc()用于替代malloc()。efree()用于替代free()。estrdup()用于替代strdup()。
estrndup()用于替代strndup()。速度要快于estrdup()而且是二进制安全的。如果你在复制之前预先知道这个字符串的长度那就推荐你使用这个函数。
ecalloc()用于替代calloc()。
erealloc()用于替代realloc()。
emalloc(), estrdup(), estrndup(), ecalloc(), 和 erealloc() 用于申请内部的内存,efree() 则用来释放这些前面这些函数申请的内存。e*() 函数所用到的内存仅对当前本地的处理请求有效,并且会在脚本执行完毕,处理请求终止时被释放。
Zend 还有一个线程安全资源管理器,这可以为多线程WEB 服务器提供更好的本地支持。不过这需要
你为所有的全局变量申请一个局部结构来支持并发线程。但是因为在写本章内容时Zend 的线程安全模式仍未完成,因此我们无法过多地涉及这个话题。
目录与文件函数
下列目录与文件函数应该在 Zend 模块内使用。它们的表现和对应的 C 语言版本完全一致,只是在线程级提供了虚拟目录的支持。
Zend 函数对应的 C 函数
V_GETCWD()getcwd()
V_FOPEN()fopen()
V_OPEN()open()
V_CHDIR()chdir()
V_GETWD()getwd()
V_CHDIR_FILE()将当前的工作目录切换到一个以文件名为参数的该文件所在的目录。
V_STAT()stat()
V_LSTAT()lstat()
字符串处理
在 Zend 引擎中,与处理诸如整数、布尔值等这些无需为其保存的值而额外申请内存的简单类型不同,如果你想从一个函数返回一个字符串,或往符号表新建一个字符串变量,或做其他类似的事情,那你就必须确认是否已经使用上面的 e*() 等函数为这些字符串申请内存。(你可能对此没有多大的感觉。无所谓,现在你只需在脑子里有点印象即可,我们稍后就会再次回到这个话题)
复杂类型
像数组和对象等这些复杂类型需要另外不同的处理。它们被出存在哈希表中,Zend 提供了一些简单的 API 来操作这些类型。php手册官方中文版
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论