您的位置:首页 > 编程语言 > PHP开发

PHP7源码分析(php7.0.17)----Embed

2018-01-13 19:05 573 查看
SAPI是PHP框架的接口层,它是进入PHP内部的入口。PHP中实现的SAPI有很多,比较典型的有:CLI、FPM、Embed、Apache2handler、Cgi、Phpdbg、litespeed。

Embed

如果我们在自己的第三方程序中也想使用PHP,那怎么办?PHP提供了一个用于这类应用场景下的SAPI,那就是Embed,它在编译后就是普通的库文件(可以选择编译为静态库或共享库),我们可以在其他的C/C++应用中调用PHP提供的API。

编译PHP时通过–enable-embed=[shared|static]指定库类型,默认共享库,编译完成后可以在PHP安装位置的/lib目录下看到生产的库文件,同时在include/php/sapi目录下会生产一个存放Embed头文件的目录。

'./configure'  '--prefix=/usr/local/webserver/php' \
'--with-config-file-path=/usr/local/webserver/php/etc' \
'--enable-fpm' '--with-fpm-user=oae' '--with-fpm-group=oae'\
'--with-mysqli' '--with-pdo-mysql' \
'--with-iconv-dir' '--with-freetype-dir' '--with-jpeg-dir' '--with-png-dir' \
'--with-zlib' '--with-libxml-dir=/usr' '--enable-xml' '--disable-rpath' \
'--enable-bcmath' '--enable-shmop' '--enable-sysvsem' \
'--enable-inline-optimization' '--with-curl' \
'--enable-mbregex' '--enable-mbstring' '--with-mcrypt' \
'--enable-ftp' '--with-gd' '--enable-gd-native-ttf' \
'--with-openssl' '--with-mhash' '--enable-pcntl' \
'--enable-sockets' '--with-xmlrpc' '--enable-zip' \
'--enable-soap' '--without-pear' '--with-gettext' \
'--enable-fileinfo' '--enable-maintainer-zts' \
--enable-embed=shared


实现

首先我们来看一下Embed的实现,实际它的逻辑非常简单,只是把PHP生命周期的几个处理函数进行了封装,它对外提供了两个API。

php_embed_init()

EMBED_SAPI_API int php_embed_init(int argc, char **argv)
{
zend_llist global_vars;
……

#ifdef ZTS
//启动SAPI
tsrm_startup(1, 1, 0, NULL);
(void)ts_resource(0);
ZEND_TSRMLS_CACHE_UPDATE();
#endif

#ifdef ZEND_SIGNALS
zend_signal_startup();
#endif
//初始化SAPI
sapi_startup(&php_embed_module);
……
//模块初始化阶段
if (php_embed_module.startup(&php_embed_module)==FAILURE) {
return FAILURE;
}
……

SG(options) |= SAPI_OPTION_NO_CHDIR;
SG(request_info).argc=argc;
SG(request_info).argv=argv;
//请求初始化阶段
if (php_request_startup()==FAILURE) {
php_module_shutdown();
return FAILURE;
}
……


php_embed_shutdown()

与php_embed_init()对应,主要完成PHP框架的关闭收尾工作

EMBED_SAPI_API void php_embed_shutdown(void)
{
//关闭请求,request shutdown阶段
php_request_shutdown((void *) 0);
//关闭模块阶段
php_module_shutdown();
sapi_shutdown();
#ifdef ZTS
tsrm_shutdown();
#endif
if (php_embed_module.ini_entries) {
free(php_embed_module.ini_entries);
php_embed_module.ini_entries = NULL;
}
}


使用

下面我们举个例子具体看一下如何在一个C程序中嵌入PHP,使用的是共享库,这个例子中我们定义的C程序将调用PHP完成一个普通PHP脚本的执行。

//my_main.c
root@11792096ccc6:/home/oae/c/embed# vi my_main.c

#include "/data/software/php7/sapi/embed/php_embed.h"

int main(int argc, char **argv)
{
zend_file_handle file_handle;
//PHP框架初始化
php_embed_init(argc,argv);
file_handle.type = ZEND_HANDLE_FILENAME;
file_handle.filename = "call.php";
//execute php script
php_execute_script(&file_handle);
//关闭PHP框架
php_embed_shutdown();
return 0;
}


//call.php
<?php
function my_func($a,$b)
{
return $a+$b;
}
echo my_func(200,300)."\n";
?>


定义完成后编译,编译时需要通过-I指定PHP的头文件目录,包括PHP、Zend、SAPI、TSRM的,通过-I以及-L 指定共享库的目录和名称。另外。还需要通过-rpath指定运行时共享库的位置。假如PHP安装路径为/usr/local/webserver/php,则编译参数为

gcc -o my_test my_main.c -I /usr/local/webserver/php/include/ \
-I /usr/local/webserver/php/include/php/ \
-I /usr/local/webserver/php/include/php/include/ \
-I /usr/local/webserver/php/include/php/main/ \
-I /usr/local/webserver/php/include/php/TSRM/ \
-I/usr/local/webserver/php/include/php/Zend/ \
-L /usr/local/webserver/php/lib/ \
-lphp -Wl,-rpath /usr/local/webserver/php/lib


编译后执行

./my_php
500
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: