编写PHP扩展一:PHP与Zend介绍
译:我在江湖丢了
原文地址:http://devzone.zend.com/303/extension-writing-part-i-introduction-to-php-and-zend/
博客地址:http://lg.uuhonghe.com/index/view?id=3
简介
何为扩展
生命周期
Hello World
创建自己的扩展
ini 配置
全局变量
设置 ini 为全局变量
完整性检查
然后哩?
简介
如果你正阅读本教程,那你可能对PHP语言的扩展编写颇感兴趣。如果不是。。。也许你读完之后会发现你对这个之前不知道的东西产生了兴趣。
本文假设读者基本了解PHP语言和用C写的PHP解释器。
让我们先确认一下你为何想写一个PHP扩展:
1、由于语言内核的抽象深度使你有一些库和系统调用无法使用PHP直接完成。
2、你希望PHP以一些不寻常的方法实现自身行为。
3、你已经写了一堆PHP代码,但你知道它可以跑得更快。
4、你有个实现了特别机智点子的代码想卖,但更重要的是你要卖的代码要能跑但不能在源码里看到。
这些都是非常正当的理由了,但要创建一个扩展,首先你得理解什么是扩展。
何为扩展?
如果你写过PHP,那你一定用过扩展了。只需要小小的几个扩展,一切PHP里的用户空间功能都在这个或那个扩展的函数组里了。大量这些函数都在标准扩展的一部分——标准扩展总共的400多个。PHP源码里捆绑了86个扩展,平均每个有大概30个函数。掐指一算,总约2500个函数。如果这还不够,PECL仓库里还提供了100个以上的附加扩展,更多的可以再网上别的地方找到。
“这些函数都在扩展里,那还有什么?”你会问,“它们扩展了什么?PHP的核心是什么?”。
PHP的内核由两部分组成。在最底层你能找到Zend引擎(简称ZE)。ZE把人能识别的脚本解析为机器识别的符号,并且在进程空间里运行这些符号。ZE同时处理内存管理,变量域和函数调用。这种区分方式的另一部门是PHP内核。PHP内核处理通信、连接和SAPI层(Server Application Programming Interface, 通常也用于指主机环境,如Apache, IIS, CLI, CGI 等),还提供了控制层对 safe_mode 和 open_basedir 的统一检测,还有和用于文件和网络I/O的用户空间函数fopen(), fread()和fwrite()相关的串流层。
生命周期
当一个SAPI启动,例如在 /usr/local/apache/bin/apachectl start 的响应中,PHP以初始化它的内核子系统开始。在这个启动全程将结束之际,会加载每个扩展的内核并调用他们的模块初始化例程(MINIT)。
这给每个扩展一个机会去初始化内部变量,分配资源,注册资源句柄,并且使用ZE注册它的函数,以便当脚本调这些函数时,ZE知道运行哪段代码。
接下来,PHP等待SAPI层来请求一个页面去处理。在CGI或者CLI SAPI的情况下,这会直接发生并且只发生一次。在Apache, IIS 或者其他一些成熟的 web 服务器SAPI中,这是在远程用户请求时发生,并且或发生多次,可能伴随着并发。无论请求如何到达,PHP以通知ZE建立一个供脚本运行的环境为开始,然后调用每个扩展的请求初始化(RINI)函数。RINI给扩展一个机会去建立自己特定的环境变量,分配请求特定的资源,或执行其他任务如审计。RINI函数行为的一个主要例子是在sessions 扩展里,如果session.auto_start项是开启的, RINI将会自动触发用户空间session_start()函数并且预设置$_SESSION变量。
一旦请求被初始化了,ZE通过翻译PHP脚本为tokens,最后转为opcodes来接管,opcodes能够单步调试和执行。
当其中一个opcodes包含的一个扩展方法被调用,ZE会捆绑上该方法的参数,并且临时性地交出控制直接方法完成。
在脚本运行完成之后,PHP调用每个扩展的请求关闭(RSHUTDOWN)函数来做最后的清理工作(例如保证会话变量到磁盘)。接着,ZE运行一个清理进程(被称为垃圾回收),该进程能有效在请求前期中使用的每个变量上执行unset()操作.
操作完成后,PHP等待SAPI请求另一个文档或者信号关闭。在CGI和CLI SAPI情况下,是没有“下一个请求”的,因此SAPI直接启动关闭进程。在关闭进程中,PHP再次遍历每个扩展,调用模块关闭(MSHUTDOWN)函数,最后关闭自己的内核子系统。
以上或许听来使人生畏,然后当你开始钻石一个工作中的扩展时,一些将逐渐清晰。
内存管理
为了防止写得很烂的扩展内存丢失,ZE用一个表明持续性的附加标识来执行它内部的内存管理器。持续性分配是很重要的,能保证内存分配持续到比一个页面请求还长。相对而言,一个不持续性分配在它分配的请求结束时被释放,无论释放函数是否被调用。例如,用户空间变量会在请求结束之后不再使用时候时分配为不持续性的。
然而也许一个扩展理论上会依赖ZE在页面请求结束时自动释放不持续性内存,这是不推荐的。内存分配会给未回收的一个更长的周期,与内存有关的资源则不太可能会被在恰当的时候关闭,没有清理工作会让这一次工作乱作一团。稍后你会看到,确保分配的数据适时清理其时是一件很简单的事情,下面我们简单的对比一下传统内存分配(必须在使用外部类库时使用)和PHP/ZE中的持续性与未持续性内存分配。
Traditional | Non-Persistent | Persistent |
---|---|---|
*
**
构建一个开发环境
现在我们已经学习了PHP和Zend引擎工作方式背后的一些理论,我猜你想运足功力开始开发了。然后在你开始前,必须得收集一些必备的工作来搭建一个满足你需要的开发环境。
首先,你需要PHP本身,因为这一系列开发工具都离不开PHP。如果你还对使用源码搭建PHP不熟悉,推荐你看下这篇文章先:http://www.php.net/install.unix.
(使用Windows开发PHP扩展的文章稍后给出)。虽然用你的linux发行版里的二进制包安全是非常诱人的,但是这些会遗漏两项在开发过程中十分方便的./configure选项。第一个就是