标签:
内容均以php-5.6.14为例.
一. 函数结构
内核中定义一个php函数使用 PHP_FUNCTION 宏 包装,扩展也不例外,该宏在 main/php.h 第343行定义;
有着一系列类似以 PHP 命名的 Zend 宏包装器,它们是:
/* PHP-named Zend macro wrappers */ /* 以PHP命名的Zend宏包装器 */ #define PHP_FN ZEND_FN #define PHP_MN ZEND_MN #define PHP_NAMED_FUNCTION ZEND_NAMED_FUNCTION #define PHP_FUNCTION ZEND_FUNCTION /* PHP_FUNCTION 就是 ZEND_FUNCTION */ #define PHP_METHOD ZEND_METHOD #define PHP_RAW_NAMED_FE ZEND_RAW_NAMED_FE #define PHP_NAMED_FE ZEND_NAMED_FE #define PHP_FE ZEND_FE #define PHP_DEP_FE ZEND_DEP_FE #define PHP_FALIAS ZEND_FALIAS #define PHP_DEP_FALIAS ZEND_DEP_FALIAS #define PHP_ME ZEND_ME #define PHP_MALIAS ZEND_MALIAS #define PHP_ABSTRACT_ME ZEND_ABSTRACT_ME #define PHP_ME_MAPPING ZEND_ME_MAPPING #define PHP_FE_END ZEND_FE_END #define PHP_MODULE_STARTUP_N ZEND_MODULE_STARTUP_N #define PHP_MODULE_SHUTDOWN_N ZEND_MODULE_SHUTDOWN_N #define PHP_MODULE_ACTIVATE_N ZEND_MODULE_ACTIVATE_N #define PHP_MODULE_DEACTIVATE_N ZEND_MODULE_DEACTIVATE_N #define PHP_MODULE_INFO_N ZEND_MODULE_INFO_N #define PHP_MODULE_STARTUP_D ZEND_MODULE_STARTUP_D #define PHP_MODULE_SHUTDOWN_D ZEND_MODULE_SHUTDOWN_D #define PHP_MODULE_ACTIVATE_D ZEND_MODULE_ACTIVATE_D #define PHP_MODULE_DEACTIVATE_D ZEND_MODULE_DEACTIVATE_D #define PHP_MODULE_INFO_D ZEND_MODULE_INFO_D /* Compatibility macros */ /* 兼容性宏 */ #define PHP_MINIT ZEND_MODULE_STARTUP_N #define PHP_MSHUTDOWN ZEND_MODULE_SHUTDOWN_N #define PHP_RINIT ZEND_MODULE_ACTIVATE_N #define PHP_RSHUTDOWN ZEND_MODULE_DEACTIVATE_N #define PHP_MINFO ZEND_MODULE_INFO_N #define PHP_GINIT ZEND_GINIT #define PHP_GSHUTDOWN ZEND_GSHUTDOWN #define PHP_MINIT_FUNCTION ZEND_MODULE_STARTUP_D /* 可用来定义模块初始时执行一些操作 */ #define PHP_MSHUTDOWN_FUNCTION ZEND_MODULE_SHUTDOWN_D /* 可用来定义模块卸载时执行一些操作 */ #define PHP_RINIT_FUNCTION ZEND_MODULE_ACTIVATE_D /* 可用来定义请求初始化时执行一些操作 */ #define PHP_RSHUTDOWN_FUNCTION ZEND_MODULE_DEACTIVATE_D /* 可用来定义请求结束时执行一些操作 */ #define PHP_MINFO_FUNCTION ZEND_MODULE_INFO_D /* 用来定义模块的信息,如phpinfo中的 */ #define PHP_GINIT_FUNCTION ZEND_GINIT_FUNCTION #define PHP_GSHUTDOWN_FUNCTION ZEND_GSHUTDOWN_FUNCTION #define PHP_MODULE_GLOBALS ZEND_MODULE_GLOBALS
ZEND_FUNCTION 在 Zend/zend_API.h 第68行,它们是:
#define ZEND_FN(name) zif_##name #define ZEND_MN(name) zim_##name #define ZEND_NAMED_FUNCTION(name) void name(INTERNAL_FUNCTION_PARAMETERS) #define ZEND_FUNCTION(name) ZEND_NAMED_FUNCTION(ZEND_FN(name)) #define ZEND_METHOD(classname, name) ZEND_NAMED_FUNCTION(ZEND_MN(classname##_##name))
函数参数 INTERNAL_FUNCTION_PARAMETERS 在 Zend/zend.h 第290行,它们是:
#define INTERNAL_FUNCTION_PARAMETERS int ht, zval *return_value, zval **return_value_ptr, zval *this_ptr, int return_value_used TSRMLS_DC #define INTERNAL_FUNCTION_PARAM_PASSTHRU ht, return_value, return_value_ptr, this_ptr, return_value_used TSRMLS_CC
也就是说,使用 PHP_FUNCTION(abc) 定义一个abc函数,预处理结果是 zif_abc(INTERNAL_FUNCTION_PARAMETERS),下面做个试验:
/* 1.c */ #include <stdio.h> #define ZEND_FN(name) zif_##name #define ZEND_MN(name) zim_##name #define ZEND_NAMED_FUNCTION(name) void name(INTERNAL_FUNCTION_PARAMETERS) #define ZEND_FUNCTION(name) ZEND_NAMED_FUNCTION(ZEND_FN(name)) #define ZEND_METHOD(classname, name) ZEND_NAMED_FUNCTION(ZEND_MN(classname##_##name)) #define INTERNAL_FUNCTION_PARAMETERS int ht, zval *return_value, zval **return_value_ptr, zval *this_ptr, int return_value_used TSRMLS_DC int main() { ZEND_FUNCTION(abc); return 0; }
使用 `gcc -E -o 1.i 1.c` 生成预处理文件 1.i ,`tail 1.i` 看文件最后的结果,内核中一个函数的形式如下:
int main() { void zif_abc(int ht, zval *return_value, zval **return_value_ptr, zval *this_ptr, int return_value_used TSRMLS_DC); return 0; }
上面 zif_abc 函数参数中还有一个看起来奇怪的东西 TSRMLS_DC,线程安全资源管理的宏;
在 TSRM/TSRM.h 第166行,它们是:
#ifdef ZTS .......... #define TSRMLS_FETCH() void ***tsrm_ls = (void ***) ts_resource_ex(0, NULL) #define TSRMLS_FETCH_FROM_CTX(ctx) void ***tsrm_ls = (void ***) ctx #define TSRMLS_SET_CTX(ctx) ctx = (void ***) tsrm_ls #define TSRMG(id, type, element) (((type) (*((void ***) tsrm_ls))[TSRM_UNSHUFFLE_RSRC_ID(id)])->element) #define TSRMLS_D void ***tsrm_ls #define TSRMLS_DC , TSRMLS_D #define TSRMLS_C tsrm_ls #define TSRMLS_CC , TSRMLS_C #else /* non ZTS */ #define TSRMLS_FETCH() #define TSRMLS_FETCH_FROM_CTX(ctx) #define TSRMLS_SET_CTX(ctx) #define TSRMLS_D void #define TSRMLS_DC #define TSRMLS_C #define TSRMLS_CC #endif /* ZTS */
TSRMLS_DC 就是 , TSRMLS_D 了,也就是 , void ***tsrm_ls ;
TSRMLS_CC就是 , TSRMLS_C 了,也就是 , tsrm_ls ;
这里有篇关于TSRM的靠谱文章:揭秘TSRM(Introspecting TSRM)
二. 参数
int ht
zval *return_value, 函数内部修改指针,函数执行完成,内核把指针指向的zval返回给用户端函数调用者。
zval **return_value_ptr,
zval *this_ptr, 如果此函数是类的方法,相当于$this
int return_value_used, 用户端调用此函数是有没有用到函数返回值,用到就是1
三. zend_API.h 中的宏函数
我们追溯该文件中定义的两个宏函数 array_init(),php_error_docref().
array_init() 在 zend_API.h 第363行:
#define array_init(arg) _array_init((arg), 0 ZEND_FILE_LINE_CC) #define array_init_size(arg, size) _array_init((arg), (size) ZEND_FILE_LINE_CC) #define object_init(arg) _object_init((arg) ZEND_FILE_LINE_CC TSRMLS_CC) #define object_init_ex(arg, ce) _object_init_ex((arg), (ce) ZEND_FILE_LINE_CC TSRMLS_CC) #define object_and_properties_init(arg, ce, properties) _object_and_properties_init((arg), (ce), (properties) ZEND_FILE_LINE_CC TSRMLS_CC) ZEND_API int _array_init(zval *arg, uint size ZEND_FILE_LINE_DC);
_array_init() 的实现在 zend_API.c 第1009行:
/* Argument parsing API -- andrei */ ZEND_API int _array_init(zval *arg, uint size ZEND_FILE_LINE_DC) /* {{{ */ { ALLOC_HASHTABLE_REL(Z_ARRVAL_P(arg)); _zend_hash_init(Z_ARRVAL_P(arg), size, ZVAL_PTR_DTOR, 0 ZEND_FILE_LINE_RELAY_CC); Z_TYPE_P(arg) = IS_ARRAY; return SUCCESS; } /* }}} */
这些API函数的存在,能让我们更方便在内核中完成某项功能。
顺藤摸瓜,ZEND_FILE_LINE_DC 在 zend.h 第217行:
#if ZEND_DEBUG #define ZEND_FILE_LINE_D const char *__zend_filename, const uint __zend_lineno #define ZEND_FILE_LINE_DC , ZEND_FILE_LINE_D #define ZEND_FILE_LINE_ORIG_D const char *__zend_orig_filename, const uint __zend_orig_lineno #define ZEND_FILE_LINE_ORIG_DC , ZEND_FILE_LINE_ORIG_D #define ZEND_FILE_LINE_RELAY_C __zend_filename, __zend_lineno #define ZEND_FILE_LINE_RELAY_CC , ZEND_FILE_LINE_RELAY_C #define ZEND_FILE_LINE_C __FILE__, __LINE__ #define ZEND_FILE_LINE_CC , ZEND_FILE_LINE_C #define ZEND_FILE_LINE_EMPTY_C NULL, 0 #define ZEND_FILE_LINE_EMPTY_CC , ZEND_FILE_LINE_EMPTY_C #define ZEND_FILE_LINE_ORIG_RELAY_C __zend_orig_filename, __zend_orig_lineno #define ZEND_FILE_LINE_ORIG_RELAY_CC , ZEND_FILE_LINE_ORIG_RELAY_C #define ZEND_ASSERT(c) assert(c) #else #define ZEND_FILE_LINE_D #define ZEND_FILE_LINE_DC #define ZEND_FILE_LINE_ORIG_D #define ZEND_FILE_LINE_ORIG_DC #define ZEND_FILE_LINE_RELAY_C #define ZEND_FILE_LINE_RELAY_CC #define ZEND_FILE_LINE_C #define ZEND_FILE_LINE_CC #define ZEND_FILE_LINE_EMPTY_C #define ZEND_FILE_LINE_EMPTY_CC #define ZEND_FILE_LINE_ORIG_RELAY_C #define ZEND_FILE_LINE_ORIG_RELAY_CC #define ZEND_ASSERT(c) #endif /* ZEND_DEBUG */
上面 __file_name 就是函数一个形参名,没特殊含义,用两个下划线有非常局部(私有)的感觉。
php_error_docref() 在 main/php.h 第322行:
BEGIN_EXTERN_C() ...... /* PHPAPI void php_error(int type, const char *format, ...); */ PHPAPI void php_error_docref0(const char *docref TSRMLS_DC, int type, const char *format, ...) PHP_ATTRIBUTE_FORMAT(printf, PHP_ATTR_FMT_OFFSET + 3, PHP_ATTR_FMT_OFFSET + 4); PHPAPI void php_error_docref1(const char *docref TSRMLS_DC, const char *param1, int type, const char *format, ...) PHP_ATTRIBUTE_FORMAT(printf, PHP_ATTR_FMT_OFFSET + 4, PHP_ATTR_FMT_OFFSET + 5); PHPAPI void php_error_docref2(const char *docref TSRMLS_DC, const char *param1, const char *param2, int type, const char * format, ...) PHP_ATTRIBUTE_FORMAT(printf, PHP_ATTR_FMT_OFFSET + 5, PHP_ATTR_FMT_OFFSET + 6); #ifdef PHP_WIN32 PHPAPI void php_win32_docref2_from_error(DWORD error, const char *param1, const char *param2 TSRMLS_DC); #endif END_EXTERN_C() #define php_error_docref php_error_docref0
例子:两步写一个color扩展的welcome函数
/* {{{ 自定义welcome */ PHP_FUNCTION(welcome) { php_printf("It works, Welcome!\n"); } /* }}} */ /* {{{ color_functions[] * * Every user visible function must have an entry in color_functions[]. 可用的函数都加到里面 */ const zend_function_entry color_functions[] = { PHP_FE(confirm_color_compiled, NULL) /* For testing, remove later. */ PHP_FE(welcome, NULL) PHP_FE_END /* Must be the last line in color_functions[] */ }; /* }}} */
make && sudo make install
运行 `php5.6.14 -r ‘welcome();‘` 就会输出:It works, Welcome!
Link: http://www.cnblogs.com/farwish/p/5248686.html
@黑眼诗人 <www.farwish.com>
标签:
原文地址:http://www.cnblogs.com/farwish/p/5248686.html