当前位置: 首页 > 后端技术 > PHP

Justforfun——宏

时间:2023-03-29 15:35:08 PHP

PHP核心架构SAPI是PHP的最顶层,也就是PHP的应用接口层。对于源代码目录,sapimain是PHP的主要代码,主要用于输入/输出、Web通信、PHP框架的初始化操作。对于源代码目录,mainZendVM是PHP解释器的主要实现,即ZendVM。对于源码目录,Zend截了一张php-src的图片,该目录有对应的PHP生命周期。SAPI的实现在每个阶段的实现上都有一些差异。比如在cli模式下,这些阶段是完全走完的,而在Fastcgi模式下,模块初始化在启动时进行一次,然后每个请求只经过请求初始化、请求脚本执行、请求关闭这几个阶段。PHP扩展开发者可以通过C/C++实现自定义函数,通过扩展嵌入到PHP中。编写扩展的步骤:通过ext目录下的ext_skel脚本生成扩展的基本框架/ext_skel--extname=module(module是你的扩展名)修改config.m4配置:设置编译配置参数,设置扩展源文件编写扩展源代码生成configure:编写完成后运行phpize(在php的bin目录下)编译&安装:./configure,make,makeinstall,然后修改php.ini文件和添加.so文件。示例操作系统:CentOSLinuxrelease7.3.1611PHP版本:PHP7.1.11生成骨架./ext_skel--extname=my_test--no-help--no-help是省略注释代码(clean点)生成目录my_test:查看C文件my_test。c/*$Salamander$*/#ifdefHAVE_CONFIG_H#include"config.h"#endif#include"php.h"#include"php_ini.h"#include"ext/standard/info.h"#include"php_my_test.h"staticintle_my_test;PHP_MINIT_FUNCTION(my_test){返回SUCCESS;}PHP_MSHUTDOWN_FUNCTION(my_test){返回SUCCESS;}PHP_RINIT_FUNCTION(my_test){#ifdefined(COMPILE_DL_MY_TEST)&&defined(urZTS)ZEND_TSRMLS_CACHE;n}SEND_UPDATE(PHP_RSHUTDOWN_FUNCTION(my_FUNCTION){returnSUCCESS;}PHP_MINFO_FUNCTION(my_test){php_info_print_table_start();php_info_print_table_header(2,"my_testsupport","enabled");php_info_print_table_end();}constzend_function_entrymy_test_functions[]={PHP_FE_END};zend_module_entrymy_test_module_entry={STANDARD_MODULE_HEADER,"my_test",my_test_functions,PHP_MINIT(my_test),PHP_MSHUTDOWN(my_test),PHP_RINIT(my_test),PHP_RSHUTDOWN(my_test),PHP_MINFO(my_test),PHP_MY_TEST_VERSION,STANDARD_MODULE_PROPERTIES};#ifdefCOMPILE_DL_MY_TEST#ifdefZTSZEND_TSRMLS_CACHE_DEFINE()#endifZEND_GET_MODULE(my_test)#endif可以注意到这里有一些宏PHP_MINIT_FUNCTIONPHP_MSHUTDOWN_FUNCTIONPHP_RINIT_FUNCTIONPHP_RSHUTDOWN_FUNCTIONPHP_MINFO_FUNCTION这些是PHP提供的钩子函数,PHP执行到不同Callbackthehookfunctionsdefinedbyeachextensionduringthestage.Afterthedefinitioniscompleted,finallysetthefunctionpointercorrespondingtozend_module_entry回顾之前的PHP生命周期,即(=>指某个阶段):PHP_MINIT_FUNCTION=>模块初始化阶段(M是模块的意思,init是初始)PHP_MSHUTDOWN_FUNCTION=>模块关闭阶段(M是模块的意思,后面是shutdown)PHP_RINIT_FUNCTION=>请求初始化(R是request的意思,init是initial)PHP_RSHUTDOWN_FUNCTION=>requestshutdown阶段(R是request的意思,后面是shutdown)PHP_MINFO_FUNCTION是指获取模块信息最后设置zend_module_entrystructurezend_module_entrymy_test_module_entry={STANDARD_MODULE_HEADER,"my_test",my_test_functions,PHP_MINIT(my_test),PHP_MSHUTDOWN(my_test),PHP_RINIT(my_test),PHP_RSHUTDOWN(my_test),PHP_MINFO(my_test),PHP_MY_TEST_VERSION,STANDARD_MODULE_PROPERTIES};获取各个钩子函数的指针,有对应的宏PHP_MINIT,PHP_MSHUTDOWN,PHP_RINIT,PHP_RSHUTDOWN,PHP_MINFO注册函数分为两个步骤:定义函数,可以使用PHP_FUNCTION()或ZEND_FUNCTION()宏来完成函数声明注册函数,PHP提供了zend_function_entry,扩展只需要为每个内部函数生成这样一个结构,然后提供zend_module_entry->functions中所有函数的结构数组。例如:PHP_FUNCTION(my_func){//具体实现}展开后voidzif_my_func(zend_execute_data*execute_data,zval*return_value){//...}zend_function_entry可以通过宏PHP_FE或ZEND_FE生成(FE是函数入口)constzend_function_entrymy_test_functions[]={PHP_FE(my_func,NULL)PHP_FE_END};my_test_functions是这个扩展注册的函数数组。最后在zend_module_entry(第三个参数)中设置(my_test),PHP_MY_TEST_VERSION,STANDARD_MODULE_PROPERTIES};函数参数解析PHP提供了一种将zend_execute_data上的参数解析为指定变量的方法。//file:Zend/zend_API.hZEND_APIintzend_parse_parameters(intnum_args,constchar*type_spec,...)num_args:参数个数,使用ZEND_NUM_ARGS()得到type_spec作为参数解析规则,为字符串,最后一个是变量参数,指定要解析的变量地址例子:PHP_FUNCTION(my_func){zval*arr;if(zend_parse_parameters(ZEND_NUM_ARGS(),"a",&a)==FAILURE){RETURN_FALSE;}...}如果有多个变量type_spec可以改成"la",l表示整型,a表示数组(另外,b:布尔值,s:字符串,o:对象),然后改成&a,&b函数的返回值可以设置return_value,但是PHP提供了一个设置返回值的宏#defineRETURN_BOOL(b){RETVAL_BOOL(b);返回;}#defineRETURN_NULL(){RETVAL_NULL();返回;}#defineRETURN_LONG(l){RETVAL_LONG(l);返回;}#defineRETURN_DOUBLE(d){RETVAL_DOUBLE(d);返回;}#defineRETURN_STR(s){RETVAL_STR(s);返回;}#defineRETURN_INTERNED_STR(s){RETVAL_INTERNED_STR(s);返回;}#defineRETURN_NEW_STR(s){RETVAL_NEW_STR(s);返回;}#defineRETURN_STR_COPY(s){RETVAL_STR_COPY(s);返回;}#defineRETURN_STRING(s){RETVAL_STRING(s);返回;}#defineRETURN_STRINGL(s,l){RETVAL_STRINGL(s,l);返回;}#defineRETURN_EMPTY_STRING(){RETVAL_EMPTY_STRING();返回;}#defineRETURN_RES(r){RETVAL_RES(r);返回;}#defineRETURN_ARR(r){RETVAL_ARR(r);返回;}#defineRETURN_OBJ(r){RETVAL_OBJ(r);返回;}#defineRETURN_ZVAL(zv,copy,dtor){RETVAL_ZVAL(zv,copy,dtor);返回;}#defineRETURN_FALSE{RETVAL_FALSE;返回;}#defineRETURN_TRUE{RETVAL_TRUE;返回;}写一个小例子写一个两个整型变量相加的函数/*$Salamander$*/#ifdefHAVE_CONFIG_H#include"config.h"#endif#include"php.h"#include"php_ini.h"#包括“ext/standard/info.h”#include“php_my_test.h”staticintle_my_test;PHP_FUNCTION(my_add){intargc=ZEND_NUM_ARGS();zend_long一个;zend_longb;如果(zend_parse_parameters(argc,"ll",&a,&b)==FAILURE)RETURN_FALSE;RETURN_LONG(a+b);}PHP_MINIT_FUNCTION(my_test){返回成功;}PHP_MSHUTDOWN_FUNCTION(my_test){返回成功;}PHP_RINIT_FUNCTION(my_test){#ifdefined(COMPILE_DL_MY_TEST)&&defined(ZTS)ZEND_TSRMLS_CACHE_UPDATE();#endifreturnSUCCESS;}PHP_RSHUTDOWN_FUNCTION(my_test){返回成功;}PHP_MINFO_FUNCTION(my_test){php_info_print_table_start();php_info_print_table_header(2,"my_testsupport","enabled");php_info_print_table_end();}constzend_function_entrymy_test_functions[]={PHP_FE(my_add,NULL)PHP_FE_END};zend_module_entrymy_test_module_entry={STANDARD_MODULE_HEADER,"my_test",my_test_functions,PHP_MINIT(my_test),PHP_MSHUTDOWN(my_test),PHP_RINIT(my_test),PHPN(RS)my_test),PHP_MINFO(my_test),PHP_MY_TEST_VERSION,STANDARD_MODULE_PROPERTIES};#ifdef编译E_DL_MY_TEST#ifdefZTSZEND_TSRMLS_CACHE_DEFINE()#endifZEND_GET_MODULE(my_test)#endifconfig.m4取消下面的注释(删除dnl即可)dnlPHP_ARG_ENABLE(my_test,是否启用my_test支持,dnl确保注释对齐:dnl[--enable-my_test启用my_test支持])然后在my_test目录下执行phpize./configure--with-php-config=/usr/local/php7.1/bin/php-configphp-config获取PHP安装信息(PHP安装路径,PHP版本、PHP源码头文件目录、LDFLAGS、依赖外部库、PHP编译参数),在php安装路径的bin目录下,如果不指定--with-php-config,在默认PHP安装路径(安装多个PHP版本时最好指定,可能会编译失败)然后make&&makeinstall得到Installingsharedextensions:/usr/local/php7.1/lib/php/extensions/no-debug-zts-20160303/修改php.ini文件,添加.sodate.timezone="Asia/Shanghai"display_errors=Onerror_reporting=E_ALLshort_open_tag=Offupload_max_filesize=50Mpost_max_size=50Mmemory_limit=512Mextension=my_test.sotestm测试函数php-r'echomy_add(1,3);'函数调用成功