正如上图(图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 源代码是不可分割的,因此就有可能在下一次的官方的源代码更新中被覆盖掉。因此,这种方式通常被认为是“不良的习惯”。由于使用极其稀少,本章将不再对此进行赘述。