设置宿主环境
现在你已经了解了PHPAPI的世界, /本2文来源[email protected]搞@^&代*@码2网搞gaodaima代码并可以使用zval以及语言内部扩展机制执行很多工作了, 是时候转移目标用它做它最擅长的事情了: 解释脚本代码.
嵌入式SAPI
回顾介绍中, php构建了一个层级系统. 最高层是提供用户空间函数和类库的所有扩展. 同时, 其下是服务API(SAPI)层, 它扮演了webserver(比如apache, iis以及命令行接口cli)的接口.
在这许多sapi实现中有一个特殊的sapi就是嵌入式sapi. 当这个sapi实现被构建时, 将会创建一个包含所有你已知的php和zend api函数以及变量的库对象, 这个库对象还包含一些额外的帮助函数和宏, 用以简化外部程序的调用.
生成嵌入式api的库和头文件和其他sapi的编译所执行的动作相同. 只需要传递–enable-embed到./configure命令中即可. 和以前一样, 使用–enable-debug对于错误报告和跟踪很有帮助.
你可能还需要打开–enable-maintainer-zts, 当然, 理由你已经耳熟能详了, 它将帮助你注意到代码的错误, 不过, 这里还有其他原因. 假设某个时刻, 你有多个应用使用php嵌入库执行脚本任务; 其中一个应用是简单的短生命周期的, 它并没有使用线程, 因此为了效率你可能想要关闭ZTS.
现在假设第二个应用使用了线程, 比如webserver, 每个线程需要跟踪自己的请求上下文. 如果ZTS被关闭, 则只有第一个应用可以使用这个库; 然而, 如果打开ZTS, 则两个应用都可以在自己的进程空间使用同一个共享对象.
当然, 你也可以同时构建两个版本, 并给它们不同的名字, 但是这相比于在不需要ZTS时包括ZTS带来的很小的效率影响更多的问题.
默认情况下, 嵌入式库将构建为libphp5.so共享对象, 或者在windows下的动态链接库, 不过, 它也可能使用可选的static关键字(–enable-embed=static)被构建为静态库.
构建为静态库的版本避免了ZTS/非ZTS的问题, 以及潜在的可能在一个系统中有多个php版本的情况. 风险在于这就意味着你的结果应用二进制将显著变大, 它将承载整个ZendEngine和PHP框架, 因此, 选择的时候就需要慎重的考虑你是否需要的是一个相对更小的库.
无论你选择那种构建方式, 一旦你执行make install, libphp5都将被拷贝到你的./configure指定的PREFIX目录下的lib/目录中. 此外还会在PREFIX/include/php/sapi/embed目录下放入名为php_embed.h的头文件, 以及你在使用php嵌入式库编译程序时需要的其他几个重要的头文件.
构建并编译一个宿主应用
究其本质而言, 库只是一个没有目的的代码集合. 为了让它工作, 你需要用以嵌入php的应用. 首先, 我们来封装一个非常简单的应用, 它启动Zend引擎并初始化PHP处理一个请求, 接着就回头进行资源的清理.
#include <sapi/embed/php_embed.h>int main(int argc, char *argv[]){ PHP_EMBED_START_BLOCK(argc,argv) PHP_EMBED_END_BLOCK() return 0;}