码迷,mamicode.com
首页 > Web开发 > 详细

[php-src]理解Php内核中的函数

时间:2016-04-16 00:40:41      阅读:383      评论:0      收藏:0      [点我收藏+]

标签:

内容均以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>

[php-src]理解Php内核中的函数

标签:

原文地址:http://www.cnblogs.com/farwish/p/5248686.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!