PHP扩展开发教程,函数传入数组
分类:web前端

PHP是一种解释型的语言,对于用户而言,我们精心的控制内存意味着easier prototyping和更少的崩溃!当我们深入到内核之后,所有的安全防线都已经被越过,最终还是要依赖于真正有责任心的软件工程师来保证系统的稳定运行。

```
场景:想要用C实现PHP的一个MVC结构的路由解析和加载文件的功能,一共要解决几个问题
1.由于MVC要加载多个C文件,所以要修正config.m4,修改config.m4内容第十行左右,去掉dnl,
PHP_ARG_WITH(dora, for route support,
dnl Make sure that the comment is aligned:
[  --with-route             Include dora support])
在下面追加到以下内容:
if test -z "$PHP_DEBUG" ; then
    AC_ARG_ENABLE(debug, [--enable-debug compile with debugging system], [PHP_DEBUG=$enableval],[PHP_DEBUG=no] )
fi

php 里面 直接 count; 一个函数搞定,c里面想判断下数组的个数却非常困难。想到php是C写的,那看看他的函数怎么写的不就行了。。。哦,天啊,,事实比我想的要复杂的多。。。1,首先源码下载下来了。。嗯,php函数都是放ext目录下的。不就一个count函数么??肯定是function count,全局搜索吧。。。--哦,老大,你搜的是C代码,C里可没有function 。那是void? 我想起来了,count返回整数类型,搜 int count(..2,在 extstandardarray.c 里面我找到了以下代码。。/* {{{ proto int count(mixed var [, int mode]) Count the number of elements in a variable (usually an array) */PHP_FUNCTION{zval *array;long mode = COUNT_NORMAL;if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z|l", &array, &mode) == FAILURE) {return;}switch (Z_TYPE_P {case IS_NULL:RETURN_LONG;break;case IS_ARRAY:RETURN_LONG (php_count_recursive (array, mode TSRMLS_CC));break;case IS_OBJECT: {#ifdef HAVE_SPLzval *retval;#endif/* first, we check if the handler is defined */if (Z_OBJ_HT_P->count_elements) {RETVAL_LONG;if (SUCCESS == Z_OBJ_HT->count_elements(array, &Z_LVAL_P(return_value) TSRMLS_CC)) {return;}}#ifdef HAVE_SPL/* if not and the object implements Countable we call its count() method */if (Z_OBJ_HT_P->get_class_entry && instanceof_function(Z_OBJCE_P, spl_ce_Countable TSRMLS_CC)) {zend_call_method_with_0_params(&array, NULL, NULL, "count", &retval);if {convert_to_long_ex(&retval);RETVAL_LONG(Z_LVAL_P;zval_ptr_dtor(&retval);}return;}#endif}default:RETURN_LONG;break;}}喝,这群人这代码写的,你可以直接扔一个对象进去,,不过我只在乎这行。。case IS_ARRAY:RETURN_LONG (php_count_recursive (array, mode TSRMLS_CC));嗯,看来要找php_count_recursive这个函数了。。就在本文件里。。static int php_count_recursive(zval *array, long mode TSRMLS_DC) /* {{{ */{long cnt = 0;zval **element;if (Z_TYPE_P == IS_ARRAY) {if (Z_ARRVAL_P->nApplyCount > 1) {php_error_docref(NULL TSRMLS_CC, E_WARNING, "recursion detected");return 0;}cnt = zend_hash_num_elements(Z_ARRVAL_P;if (mode == COUNT_RECURSIVE) {HashPosition pos;for (zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P, &pos);zend_hash_get_current_data_ex(Z_ARRVAL_P, &element, &pos) == SUCCESS;zend_hash_move_forward_ex(Z_ARRVAL_P, &pos)) {Z_ARRVAL_P->nApplyCount++;cnt += php_count_recursive(*element, COUNT_RECURSIVE TSRMLS_CC);Z_ARRVAL_P->nApplyCount--;}}}return cnt;}嗯,他们找我干活了,下次再找吧。。。这么复杂的count还不如我自己写个了........以下代码证明了我初始想验证的观点。。#include <stdio.h>#include <stdlib.h>void changeArr(int arr[]);int main(int argc, char *argv[]){ int charr[2]; charr[0] = 1; charr[1] = 2; changeArr; printf("charr[0] = %i", charr[0]); system; return 0;}void changeArr(int arr[]){arr[0] = 100;}主要是这行 changeArr; 当函数传入数组时,,数组值被直接改变,,而不用像php中要用引用,,&。

1、线程安全宏定义

最后一行,加载所需所有C文件,如下:
  PHP_NEW_EXTENSION(dora, dora.c common/utilts.c loader/loader.c route/route.c controller/controller.c model/model.c, $ext_shared,, -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1)
  PHP_ADD_BUILD_DIR([$ext_builddir/common])
  PHP_ADD_BUILD_DIR([$ext_builddir/loader])
  PHP_ADD_BUILD_DIR([$ext_builddir/route])
  PHP_ADD_BUILD_DIR([$ext_builddir/controller])
  PHP_ADD_BUILD_DIR([$ext_builddir/model])
 
```
```c

在TSRM/TSRM.h文件中有如下定义

#include "utilts.h"
#include "php_ini.h"
#include "ext/standard/info.h"
#include "Zend/zend_list.h"
#include "Zend/zend_interfaces.h"

#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

//执行PHP文件函数
int zend_execute_scripts_ext(char *filepath){

在ext/xsl/php_xsl.h有这么一段话

    zval retval;

/* In every utility function you add that needs to use variables.                                                                   
   in php_xsl_globals, call TSRM_FETCH(); after declaring other.
   variables used by that function, or better yet, pass in TSRMLS_CC
   after the last function argument and declare your utility function
   with TSRMLS_DC after the last declared argument.  Always refer to
   the globals in your function as XSL_G(variable).  You are.
   encouraged to rename these macros something shorter, see
   examples in any other php module directory.
*/

    zend_file_handle zfd;
    zfd.type = ZEND_HANDLE_FILENAME;
    zfd.filename = filepath;
    zfd.free_filename = 0;
    zfd.opened_path = NULL;

1.在方法定义时加上TSRMLS_D(如果方法没有参数用这个)或者TSRMLS_DC(有1个以上的参数)

    //zend_execute_scripts(int type, zval *retval, int file_count, ...);
    //FAILURE OR SUCCESS
    return  zend_execute_scripts(ZEND_INCLUDE TSRMLS_CC,&retval,1,&zfd);     

2.在方法调用时用TSRMLS_C(如果方法没有参数用这个)或者TSRMLS_CC(有1个以上的参数)

}

应该可以这样理解

//调用类中的方法
int call_user_class_method(zval *retval, zend_class_entry *obj_ce,
                           zval *obj, zval func,  uint32_t params_count, zval params[]){

第一个后缀字母D表示定义,即D=Define,第一个后缀字母C表示调用,即C=Call,而第二个后缀字母C是不是表示逗号呢? C=Comma (逗号)

    HashTable *function_table;

TSRMLS_D就是定义了,所以是  void ***tsrm_ls

    if(obj) {
                function_table = &Z_OBJCE_P(obj)->function_table;
        }else{
                function_table = (CG(function_table));
    }

TSRMLS_DC是带逗号的定义,所以是 , void ***tsrm_ls

    zend_fcall_info fci;  
    fci.size = sizeof(fci);  
    fci.function_table = function_table;  
    fci.object =  obj ? Z_OBJ_P(obj) : NULL;;
    fci.function_name = func;   
    fci.retval = retval;  
    fci.param_count = params_count;  
    fci.params = params;  
    fci.no_separation = 1;  
    fci.symbol_table = NULL;  

TSRMLS_C是调用,即tsrm_ls

 
    //FAILURE OR SUCCESS
    return  zend_call_function(&fci, NULL TSRMLS_CC);         //函数调用结束。  

TSRMLS_CC是调用并带逗号,即 ,tsrm_ls

}

所以一个是形参、一个是实参

```
```c
3.修改php_route.h头文件内容

可以这样使用

在第五十行左右,加入以下内容

int php_myext_action(int action_id, char *message TSRMLS_DC);
php_myext_action(42, "The meaning of life" TSRMLS_CC);

//定义类
extern zend_class_entry *route_ce;
//定义loader类中的方法
PHP_METHOD(route_ce,__construct);
PHP_METHOD(route_ce,run);
```
```c
4.修改route.c文件内容

一般推荐使用tsrm_ls指针定义的方式来保证线程安全

/**
 * 声明构造函数
 * @param
 * @return
 */
ZEND_METHOD(route,__construct){

TSRMLS_FETCH调用需要一定的处理时间。这在单次迭代中并不明显,但是随着你的线程数增多,随着你调用TSRMLS_FETCH()的点的增多,你的扩展就会显现出这个瓶颈。因此,请谨慎的使用它。 注意:为了和c++编译器兼容,请确保将TSRMLS_FETCH()和所有变量定义放在给定块作用域的顶部(任何其他语句之前)。因为TSRMLS_FETCH()宏自身有多种不同的解析方式,因此最好将它作为变量定义的最后一行

 
    zval *app_dir;

2、PHP的生命周期

    if( zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &app_dir) == FAILURE )
    {
        RETURN_NULL();
    }
    //zend_update_static_property_stringl(zend_class_entry *scope, const char *name, size_t name_length, const char *value, size_t value_length);
    zend_update_static_property(route_ce, "app_dir", sizeof("app_dir")-1, app_dir TSRMLS_CC);

PHP的最多的两种运行模式是WEB模式、CLI模式,无论哪种模式,PHP工作原理都是一样的,作为一种SAPI运行。

}

1、当我们在终端敲入php这个命令的时候,它使用的是CLI。

/**
 * 加载view
 * @param
 * @return
 */
ZEND_METHOD(route,run){

它就像一个web服务器一样来支持php完成这个请求,请求完成后再重新把控制权交给终端。

      zend_string* controller_name = zend_string_init("Index",strlen("Index"),0);
      zend_string* action_name     = zend_string_init("Index",strlen("Index"),0);

2、当使用Apache作为宿主时,当一个请求到来时,PHP会来支持完成这个请求

      zval *c_result;
      zval *a_result;
      int flag;

PHP_MINIT_FUNCTION  初始化module时运行
PHP_MSHUTDOWN_FUNCTION  当module被卸载时运行
PHP_RINIT_FUNCTION  当一个REQUEST请求初始化时运行
PHP_RSHUTDOWN_FUNCTION  当一个REQUEST请求结束时运行
PHP_MINFO_FUNCTION  这个是设置phpinfo中这个模块的信息
PHP_GINIT_FUNCTION  初始化全局变量时
PHP_GSHUTDOWN_FUNCTION  释放全局变量时

      //设置站点目录
      zval *app_dir = zend_read_static_property(Z_OBJCE_P(getThis()), "app_dir", sizeof("app_dir")-1, 0 TSRMLS_DC);

比如PHP_GINIT_FUNCTION

      //获取GET请求参数hashtable
      zval *get_arr = &PG(http_globals)[TRACK_VARS_GET];
      HashTable *ht= HASH_OF(get_arr);
      //int array_count = zend_hash_num_elements(Z_ARRVAL_P(get_arr));     

PHP_GINIT_FUNCTION(test)
{
  /** 初始化全局变量 */
}
//对应的C代码
void zm_globals_ctor_test (zend_test_globals *test_globals TSRMLS_DC)
{
  /** 初始化全局变量 */
}
//在线程退出时,需要将之前自己申请的资源释放时,可以使用 PHP_GSHUTDOWN_FUNCTION来注册析构函数。
PHP_GSHUTDOWN_FUNCTION(test)
{
  /** 清除全局变量 */
}
//对应的C代码
void zm_globals_dtor_test (zend_test_globals *test_globals TSRMLS_DC)
{
  /** 清除全局变量 */
}

      //获取controller_name
      zend_string *c_key= zend_string_init("controller", sizeof("controller")-1, 0);

这里有一段代码,可以测试一下

      if ((c_result = zend_hash_find(ht, c_key)) != NULL) {
      
            controller_name = zval_get_string(c_result);
        
      }else{

int minit_time;
PHP_MINIT_FUNCTION(test)
{
  minit_time = time(NULL);
  return SUCCESS;
}
PHP_MSHUTDOWN_FUNCTION(test)
{
  FILE *fp=fopen("mshutdown.txt","a+");
  fprintf(fp,"%ldn",time(NULL));
  fclose(fp);
  return SUCCESS;
}
int rinit_time;
PHP_RINIT_FUNCTION(test)
{
  rinit_time = time(NULL);
  return SUCCESS;
}
PHP_RSHUTDOWN_FUNCTION(test)
{
  FILE *fp=fopen("rshutdown.txt","a+");
  fprintf(fp,"%ldn",time(NULL));
  fclose(fp);
  return SUCCESS;
}
PHP_MINFO_FUNCTION(test)
{
  php_info_print_table_start();
  php_info_print_table_header(, "module info", "enabled");
  php_info_print_table_end();
  /* Remove comments if you have entries in php.ini
  DISPLAY_INI_ENTRIES();
  */
}
PHP_FUNCTION(test)
{
  php_printf("%d",time_of_minit);
  php_printf("%d",time_of_rinit);
  return;
}

            zend_error_noreturn(E_CORE_ERROR,  "Couldn't find controller param in url.");

3、段错误调试

      }
      //释放key的变量
      zend_string_release(c_key);

Linux下的C程序常常会因为内存访问错误等原因造成segment fault(段错误)此时如果系统core dump功能是打开的,那么将会有内存映像转储到硬盘上来,之后可以用gdb对core文件进行分析,还原系统发生段错误时刻的堆栈情况。这对于我们发现程序bug很有帮助。
使用ulimit -a可以查看系统core文件的大小限制;使用ulimit -c [kbytes]可以设置系统允许生成的core文件大小。

      //获取action_name
      zend_string *a_key= zend_string_init("action", sizeof("action")-1, 0);

ulimit -c 0 不产生core文件
ulimit -c 100 设置core文件最大为100k
ulimit -c unlimited 不限制core文件大小

      if ((a_result = zend_hash_find(ht, a_key)) != NULL) {

步骤:

            action_name = zval_get_string(a_result);
            //php_printf("%sn", Z_STRVAL_P(a_result));
            //php_printf("%sn", zval_get_string(a_result));
      }else{

1、当发生段错误时,我们查看ulimit -a (core file size (blocks, -c) 0)并没有文件,
2、设置 :ulimit -c unlimited 不限制core文件大小
3、运行程序 ,发生段错误时会自动记录在core中 (php -f WorkWithArray.php)
4、ls -al core.* 在那个文件下(-rw------- 1 leconte leconte 139264 01-06 22:3 1 core.2065)
5、使用gdb 运行程序和段错误记录的文件。(gdb ./test core.2065)
6、会提哪行有错。

            zend_error_noreturn(E_CORE_ERROR,"Couldn't find action param in url.");

很多系统默认的core文件大小都是0,我们可以通过在shell的启动脚本/etc/bashrc或者~/.bashrc等地方来加入 ulimit -c 命令来指定core文件大小,从而确保core文件能够生成。
除此之外,还可以在/proc/sys/kernel/core_pattern里设置core文件的文件名模板,详情请看core的官方man手册。

      }

4、常见的变量操作宏

      //释放key的变量
      zend_string_release(a_key);

CG    -> Complier Global      编译时信息,包括函数表等(zend_globals_macros.h:32)
EG    -> Executor Global      执行时信息(zend_globals_macros.h:43)
PG    -> PHP Core Global      主要存储php.ini中的信息
SG    -> SAPI Global          SAPI信息

      //拼装controller文件路径
      char *path = Z_STRVAL_P(app_dir);
      char *c_2 = "controllers/";
      strcat(path,c_2);

1、SG  针对SAPI信息 在main/SAPI.h文件中

      //zend_string->char *
      char *c_3 = ZSTR_VAL(controller_name);
      strcat(path,c_3);

typedef struct _sapi_globals_struct {
  void *server_context;
  sapi_request_info request_info;
  sapi_headers_struct sapi_headers;
  int read_post_bytes;
  unsigned char headers_sent;
  struct stat global_stat;
  char *default_mimetype;
  char *default_charset;
  HashTable *rfc1867_uploaded_files;
  long post_max_size;
  int options;
  zend_bool sapi_started;
  double global_request_time;
  HashTable known_post_content_types;
  zval *callback_func;
  zend_fcall_info_cache fci_cache;
  zend_bool callback_run;
} sapi_globals_struct;

      char *c_4 = ".php";
      strcat(path,c_4);

看一下SG的定义

      //php_printf("%sn", c_1);
      // php_printf("%sn", controller_name);
      // php_printf("%sn", action_name);
      //PHPWRITE(Z_STRVAL_P(app_dir), Z_STRLEN_P(app_dir));

BEGIN_EXTERN_C()
#ifdef ZTS
# define SG(v) TSRMG(sapi_globals_id, sapi_globals_struct *, v)
SAPI_API extern int sapi_globals_id;
#else
# define SG(v) (sapi_globals.v)
extern SAPI_API sapi_globals_struct sapi_globals;
#endif
SAPI_API void sapi_startup(sapi_module_struct *sf);
SAPI_API void sapi_shutdown(void);
SAPI_API void sapi_activate(TSRMLS_D);
SAPI_API void sapi_deactivate(TSRMLS_D);
SAPI_API void sapi_initialize_empty_request(TSRMLS_D);
END_EXTERN_C()

      //加载执行controller文件
      flag = zend_execute_scripts_ext(c_1);

成员都在sapi_globals_struct这里了

      if(flag == FAILURE){

那么我么可以这样调用

            zend_error_noreturn(E_CORE_ERROR,"Couldn't find file: %s.",c_1);

SG(default_mimetype)
SG(request_info).request_uri

      }

可以感受一下这么一段代码

      //查找controller对应的
      //zend_class_entry *zend_lookup_class(zend_string *name);
      zend_class_entry *controller_ce = zend_lookup_class(controller_name);

static int sapi_cgi_send_headers(sapi_headers_struct *sapi_headers TSRMLS_DC)
{
  char buf[SAPI_CGI_MAX_HEADER_LENGTH];
  sapi_header_struct *h;
  zend_llist_position pos;
  long rfc2616_headers = 0;
  if(SG(request_info).no_headers == 1) {
    return SAPI_HEADER_SENT_SUCCESSFULLY;
  }
  if (SG(sapi_headers).http_response_code != 200) {
    int len;
    len = sprintf(buf, "Status: %drn", SG(sapi_headers).http_response_code);
    PHPWRITE_H(buf, len);
  }
  if (SG(sapi_headers).send_default_content_type) {
    char *hd;
    hd = sapi_get_default_content_type(TSRMLS_C);
    PHPWRITE_H("Content-type:", sizeof("Content-type: ")-1);
    PHPWRITE_H(hd, strlen(hd));
    PHPWRITE_H("rn", 2);
    efree(hd);
  }
  h = zend_llist_get_first_ex(&sapi_headers->headers, &pos);
  while (h) {
    PHPWRITE_H(h->header, h->header_len);
    PHPWRITE_H("rn", 2);
    h = zend_llist_get_next_ex(&sapi_headers->headers, &pos);
  }
  PHPWRITE_H("rn", 2);
  return SAPI_HEADER_SENT_SUCCESSFULLY;
}

      if(controller_ce == NULL){

 2、EG  Executor Globals

            zend_error_noreturn(E_CORE_ERROR,"Couldn't find file: %s.",c_1);
      }

EG获取的是struct _zend_execution_globals结构体中的数据

      zval obj;
      object_init_ex(&obj, controller_ce);

struct _zend_execution_globals {
 ...
 HashTable symbol_table;  /* 全局作用域,如果没有进入函数内部,全局=活动 */
 HashTable *active_symbol_table; /* 活动作用域,当前作用域 */
 ...
}

      
      zval function_name;
      ZVAL_STRING(&function_name,ZSTR_VAL(action_name));

通常,使用EG(symbol_table)获取的是全局作用域中的符号表,使用EG(active_symbol_table)获取的是当前作用域下的符号表

      
      flag = call_user_class_method(return_value, controller_ce, &obj, function_name, 0, NULL);

例如 来定义$foo = 'bar'

      if(flag == FAILURE){

zval *fooval;
 
MAKE_STD_ZVAL(fooval);
ZVAL_STRING(fooval, "bar", 1);
ZEND_SET_SYMBOL(EG(active_symbol_table), "foo", fooval);

            zend_error_noreturn(E_CORE_ERROR,
                                "Couldn't find implementation for method %s%s%s",
                                controller_ce ? ZSTR_VAL(controller_ce->name) : "",
                                controller_ce ? "::" : "",
                                function_name);
        
      }

或者从符号表中查找$foo

      //RETURN_ZVAL(get_arr, 1, 0);

zval **fooval;
if(zend_hash_find(&EG(symbol_table), "foo", sizeof("foo"), (void **)&fooval) == SUCCESS) {
    RETURN_STRINGL(Z_STRVAL_PP(fooval), Z_STRLEN_PP(fooval));
} else {
    RETURN_FALSE;
}

}

上面的代码中,EG(active_symbol_table) == &EG(symbol_table)

const zend_function_entry route_functions[] = {

3、CG() 用来访问核心全局变量。(zend/zend_globals_macros.h)

    //注册route类中的方法
    ZEND_ME(route, __construct, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR)
    ZEND_ME(route,run,NULL,ZEND_ACC_PUBLIC)

4、PG() PHP全局变量。我们知道php.ini会映射一个或者多个PHP全局结构。(main/php_globals.h)

    PHP_FE_END    /* Must be the last line in route_functions[] */
};

5、FG() 文件全局变量。大多数文件I/O或相关的全局变量的数据流都塞进标准扩展出口结构。(ext/standard/file.h)

PHP_MINIT_FUNCTION(route)
{

5、获取变量的类型和值

    //注册route类
    zend_class_entry ce;

#define Z_TYPE(zval)        (zval).type
#define Z_TYPE_P(zval_p)    Z_TYPE(*zval_p)
#define Z_TYPE_PP(zval_pp)  Z_TYPE(**zval_pp)

    //define INIT_NS_CLASS_ENTRY(class_container, ns, class_name, functions)
    INIT_NS_CLASS_ENTRY(ce,"Dora" ,"Route", route_functions);
    route_ce = zend_register_internal_class(&ce TSRMLS_CC);

比如获取一个变量的类型

    //声明一个静态数据成员app_dir
    //zend_declare_property_string(zend_class_entry *ce, const char *name, size_t name_length, const char *value, int access_type);
    zend_declare_property_string(route_ce, "app_dir", strlen("app_dir"), "",ZEND_ACC_PUBLIC|ZEND_ACC_STATIC TSRMLS_DC);     

void describe_zval(zval *foo)
{
  if ( Z_TYPE_P(foo) == IS_NULL )
  {
    php_printf("这个变量的数据类型是: NULL");
  }
  else
  {
    php_printf("这个变量的数据类型不是NULL,这种数据类型对应的数字是: %d", Z_TYPE_P(foo));
  }
}

    return SUCCESS;
}
```
```c
5.编译安装
phpize
./configure --with-php-config=/usr/bin/php-config
make && make install

有这么几种类型

```
```c
6.php7创建类所有到的知识点

#define IS_NULL     0
#define IS_LONG     1
#define IS_DOUBLE   2
#define IS_BOOL     3
#define IS_ARRAY    4
#define IS_OBJECT   5
#define IS_STRING   6
#define IS_RESOURCE 7
#define IS_CONSTANT 8
#define IS_CONSTANT_ARRAY   9
#define IS_CALLABLE 10

常见的变量操作宏

php_printf()函数是内核对printf()函数的一层封装,我们可以像使用printf()函数那样使用它,以一个P结尾的宏的参数大多是*zval型变量。 此外获取变量类型的宏还有两个,分别是Z_TYPE和Z_TYPE_PP,前者的参数是zval型,而后者的参数则是**zval

CG    -> Complier Global      编译时信息,包括函数表等(zend_globals_macros.h:32)
EG    -> Executor Global      执行时信息(zend_globals_macros.h:43)
PG    -> PHP Core Global      主要存储php.ini中的信息
SG    -> SAPI Global          SAPI信息

比如gettype函数的实现

//===============================================================================
PHP7中的zval的类型:
/* regular data types */
define IS_UNDEF                    0
define IS_NULL                     1
define IS_FALSE                    2
define IS_TRUE                     3
define IS_LONG                     4
define IS_DOUBLE                   5
define IS_STRING                   6
define IS_ARRAY                    7
define IS_OBJECT                   8
define IS_RESOURCE                 9
define IS_REFERENCE                10

//开始定义php语言中的函数gettype
PHP_FUNCTION(gettype)
{
  //arg间接指向调用gettype函数时所传递的参数。是一个zval**结构
  //所以我们要对他使用__PP后缀的宏。
  zval **arg;
  //这个if的操作主要是让arg指向参数~
  if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z", &arg) == FAILURE) {
    return;
  }
  //调用Z_TYPE_PP宏来获取arg指向zval的类型。
  //然后是一个switch结构,RETVAL_STRING宏代表这gettype函数返回的字符串类型的值
  switch (Z_TYPE_PP(arg)) {
    case IS_NULL:
      RETVAL_STRING("NULL", 1);
      break;
    case IS_BOOL:
      RETVAL_STRING("boolean", 1);
      break;
    case IS_LONG:
      RETVAL_STRING("integer", 1);
      break;
    case IS_DOUBLE:
      RETVAL_STRING("double", 1);
      break;
    case IS_STRING:
      RETVAL_STRING("string", 1);
      break;
    case IS_ARRAY:
      RETVAL_STRING("array", 1);
      break;
    case IS_OBJECT:
      RETVAL_STRING("object", 1);
      break;
    case IS_RESOURCE:
      {
        char *type_name;
        type_name = zend_rsrc_list_get_rsrc_type(Z_LVAL_PP(arg) TSRMLS_CC);
        if (type_name) {
          RETVAL_STRING("resource", 1);
          break;
        }
      }
    default:
      RETVAL_STRING("unknown type", 1);
  }
}

define IS_CONSTANT                 11
define IS_CONSTANT_AST             12

获取变量的值,有这么多宏来获取

define _IS_BOOL                    13
define IS_CALLABLE                 14

 

define IS_INDIRECT                 15
define IS_PTR                      17

Long

Boolean

Double

String value

String length

Z_LVAL( )

 

Z_BVAL( )

 

Z_DVAL( )

 

Z_STRVAL( )

 

Z_STRLEN( )

 

Z_LVAL_P( )

 

Z_BVAL_P( )

 

Z_DVAL_P( )

 

Z_STRVAL_P( )

 

Z_STRLEN_P( )

 

Z_LVAL_PP( )

 

Z_BVAL_PP( )

 

Z_DVAL_PP( )

 

Z_STRVAL_PP( )

 

Z_STRLEN_PP( )

 

HashTable

Object

Object properties

Object class entry

Resource value

Z_ARRVAL( )

 

Z_OBJ( )

 

Z_OBJPROP( )

 

Z_OBJCE( )

 

Z_RESVAL( )

 

Z_ARRVAL_P( )

 

Z_OBJ_P( )

 

Z_OBJPROP_P( )

 

Z_OBJCE_P( )

 

Z_RESVAL_P( )

 

Z_ARRVAL_PP( )

 

Z_OBJ_PP( )

 

Z_OBJPROP_PP( )

 

Z_OBJCE_PP( )

 

Z_RESVAL_PP( )

 

//===============================================================================
PHP7中获取的zval赋值:

rot13函数的实现

  • ZVAL_STRING(zv, str, 1);
  • ZVAL_STRING(zv, str);
  • ZVAL_STRINGL(zv, str, len, 1);
  • ZVAL_STRINGL(zv, str, len);
  • ZVAL_STRING(zv, str, 0);
  • ZVAL_STRING(zv, str);
  • efree(str);
  • ZVAL_STRINGL(zv, str, len, 0);
  • ZVAL_STRINGL(zv, str, len);
PHP_FUNCTION(rot13)
{
 zval **arg;
 char *ch, cap;
 int i;
  
 if (ZEND_NUM_ARGS( ) != 1 || zend_get_parameters_ex(1, &arg) == FAILURE) {
   WRONG_PARAM_COUNT;
 }
 *return_value = **arg;
 zval_copy_ctor(return_value);
 convert_to_string(return_value);
  
 for(i=0, ch=return_value->value.str.val;
   i<return_value->value.str.len; i++, ch++) {
    cap = *ch & 32;
    *ch &= ~cap;
    *ch = ((*ch>='A') && (*ch<='Z') ? ((*ch-'A'+13) % 26 + 'A') : *ch) | cap;
  }
}

//===============================================================================

要获取变量的值,也应该使用Zend定义的宏进行访问。对于简单的标量数据类型、Boolean,long,double, 使用Z_BVAL, Z_LVAL, Z_DVAL

PHP7中获取的zval的值和长度:
define Z_LVAL(zval)                (zval).value.lval
define Z_LVAL_P(zval_p)            Z_LVAL(*(zval_p))

void display_values(zval boolzv, zval *longpzv, zval **doubleppzv)
{
 if (Z_TYPE(boolzv) == IS_BOOL) {
  php_printf("The value of the boolean is : %sn", Z_BVAL(boolzv) ? "true" : "false");
 }
 if(Z_TYPE_P(longpzv) == IS_LONG) {
  php_printf("The value of the long is: %ldn", Z_LVAL_P(longpzv));
 }
 if(Z_TYPE_PP(doubleppzv) == IS_DOUBLE) {
  php_printf("The value of the double is : %fn", Z_DVAL_PP(doubleppzv));
 }
}

define Z_DVAL(zval)                (zval).value.dval
define Z_DVAL_P(zval_p)            Z_DVAL(*(zval_p))

对于字符串类型,因为它含有两个字段char * (Z_STRVAL) 和 int (Z_STRLEN),因此需要用两个宏来进行取值,因为需要二进制安全的输出这个字符串

define Z_STR(zval)                 (zval).value.str
define Z_STR_P(zval_p)             Z_STR(*(zval_p))

void display_string(zval *zstr)
{
 if (Z_TYPE_P(zstr) != IS_STRING) {
  php_printf("The wronng datatype was passed!n");
  return ;
 }
 PHPWRITE(Z_STRVAL_P(zstr), Z_STRLEN_P(zstr));
}

define Z_STRVAL(zval)              ZSTR_VAL(Z_STR(zval))
define Z_STRVAL_P(zval_p)          Z_STRVAL(*(zval_p))

因为数组在zval中是以HashTable形式存在的,因此使用Z_ARRVAL()进行访问

define Z_STRLEN(zval)              ZSTR_LEN(Z_STR(zval))
define Z_STRLEN_P(zval_p)          Z_STRLEN(*(zval_p))

void display_zval(zval *value)
{
  switch (Z_TYPE_P(value)) {
    case IS_NULL:
      /* 如果是NULL,则不输出任何东西 */
      break;
 
    case IS_BOOL:
      /* 如果是bool类型,并且true,则输出1,否则什么也不干 */
      if (Z_BVAL_P(value)) {
        php_printf("1");
      }
      break;
    case IS_LONG:
      /* 如果是long整型,则输出数字形式 */
      php_printf("%ld", Z_LVAL_P(value));
      break;
    case IS_DOUBLE:
      /* 如果是double型,则输出浮点数 */
      php_printf("%f", Z_DVAL_P(value));
      break;
    case IS_STRING:
      /* 如果是string型,则二进制安全的输出这个字符串 */
      PHPWRITE(Z_STRVAL_P(value), Z_STRLEN_P(value));
      break;
    case IS_RESOURCE:
      /* 如果是资源,则输出Resource #10 格式的东东 */
      php_printf("Resource #%ld", Z_RESVAL_P(value));
      break;
    case IS_ARRAY:
      /* 如果是Array,则输出Array5个字母! */
      php_printf("Array");
      break;
    case IS_OBJECT:
      php_printf("Object");
      break;
    default:
      /* Should never happen in practice,
       * but it's dangerous to make assumptions
       */
       php_printf("Unknown");
       break;
  }
}

define Z_STRHASH(zval)             ZSTR_HASH(Z_STR(zval))
define Z_STRHASH_P(zval_p)         Z_STRHASH(*(zval_p))

一些类型转换函数

define Z_ARR(zval)                 (zval).value.arr
define Z_ARR_P(zval_p)             Z_ARR(*(zval_p))

ZEND_API void convert_to_long(zval *op);
ZEND_API void convert_to_double(zval *op);
ZEND_API void convert_to_null(zval *op);
ZEND_API void convert_to_boolean(zval *op);
ZEND_API void convert_to_array(zval *op);
ZEND_API void convert_to_object(zval *op);
ZEND_API void _convert_to_string(zval *op ZEND_FILE_LINE_DC);

define Z_ARRVAL(zval)              Z_ARR(zval)
define Z_ARRVAL_P(zval_p)          Z_ARRVAL(*(zval_p))

6、常量的实例化

define Z_OBJ(zval)                 (zval).value.obj
define Z_OBJ_P(zval_p)             Z_OBJ(*(zval_p))

我们可以这样实例化

define Z_OBJ_HT(zval)              Z_OBJ(zval)->handlers
define Z_OBJ_HT_P(zval_p)          Z_OBJ_HT(*(zval_p))

PHP_MINIT_FUNCTION(consts) //模块初始化时定义常量
{
  REGISTER_LONG_CONSTANT("CONSTS_MEANING_OF_LIFE", 42, CONST_CS | CONST_PERSISTENT);
  REGISTER_DOUBLE_CONSTANT("CONSTS_PI", 3.1415926, CONST_PERSISTENT);
  REGISTER_STRING_CONSTANT("CONSTS_NAME", "leon", CONST_CS|CONST_PERSISTENT);
}
PHP_RINIT_FUNCTION(consts) //每次请求时定义常量
{
  char buffer[40];
  srand((int)time(NULL));
  snprintf(buffer, sizeof(buffer), "%d", rand());
  REGISTER_STRING_CONSTANT("CONSTS_RAND", estrdup(buffer), CONST_CS);
  return SUCCESS;
}

define Z_OBJ_HANDLER(zval, hf)     Z_OBJ_HT((zval))->hf
define Z_OBJ_HANDLER_P(zv_p, hf)   Z_OBJ_HANDLER(*(zv_p), hf)

常见的宏

define Z_OBJ_HANDLE(zval)          (Z_OBJ((zval)))->handle
define Z_OBJ_HANDLE_P(zval_p)      Z_OBJ_HANDLE(*(zval_p))

/*注册LONG类型常量*/
#define REGISTER_LONG_CONSTANT(name, lval, flags)  zend_register_long_constant((name), sizeof(name), (lval), (flags), module_number TSRMLS_CC)

define Z_OBJCE(zval)               (Z_OBJ(zval)->ce)
define Z_OBJCE_P(zval_p)           Z_OBJCE(*(zval_p))

 /*注册double类型常量*/
#define REGISTER_DOUBLE_CONSTANT(name, dval, flags)  zend_register_double_constant((name), sizeof(name), (dval), (flags), module_number TSRMLS_CC)

define Z_OBJPROP(zval)             Z_OBJ_HT((zval))->get_properties(&(zval))
define Z_OBJPROP_P(zval_p)         Z_OBJPROP(*(zval_p))

/*注册STRING类型常量*/
#define REGISTER_STRING_CONSTANT(name, str, flags)  zend_register_string_constant((name), sizeof(name), (str), (flags), module_number TSRMLS_CC)

define Z_OBJDEBUG(zval,tmp)        (Z_OBJ_HANDLER((zval),get_debug_info)?Z_OBJ_HANDLER((zval),get_debug_info)(&(zval),&tmp):(tmp=0,Z_OBJ_HANDLER((zval),get_properties)?Z_OBJPROP(zval):NULL))
define Z_OBJDEBUG_P(zval_p,tmp)    Z_OBJDEBUG(*(zval_p), tmp)

/*注册STRING类型常量*/
#define REGISTER_STRINGL_CONSTANT(name, str, len, flags)  zend_register_stringl_constant((name), sizeof(name), (str), (len), (flags), module_number TSRMLS_CC)

define Z_RES(zval)                 (zval).value.res
define Z_RES_P(zval_p)             Z_RES(*zval_p)

7、全局变量

define Z_RES_HANDLE(zval)          Z_RES(zval)->handle
define Z_RES_HANDLE_P(zval_p)      Z_RES_HANDLE(*zval_p)

#php-fpm 生成 POST|GET|COOKIE|SERVER|ENV|REQUEST|FILES全局变量的流程
php_cgi_startup() -> php_module_startup() -> php_startup_auto_globals() -> 保存变量到symbol_table符号表
php_cgi_startup()在 fpm/fpm/fpm_main.c中定义
php_module_startup() 在main/main.c中定义
php_startup_auto_globals() 在main/php_variables.h中定义
zend_hash_update(&EG(symbol_table), "_GET", sizeof("_GET") + 1, &vars, sizeof(zval *), NULL);
/* 读取$_SERVER变量 */
static PHP_FUNCTION(print_server_vars) {
  zval **val;
  if (zend_hash_find(&EG(symbol_table), "_SERVER", sizeof("_SERVER"), (void **)&val) == SUCCESS) {
    RETURN_ZVAL(*val, 1, 0);
  }else{
   RETURN_FALSE;
  }
}
/* 读取$_SERVER[$name] */
ZEND_BEGIN_ARG_INFO(print_server_var_arginfo, 0)
  ZEND_ARG_INFO(0, "name")
ZEND_END_ARG_INFO()
static PHP_FUNCTION(print_server_var) {
  char *name;
  int name_len;
  zval **val;
  HashTable *ht_vars = NULL;
  HashPosition pos;
  zval **ret_val;
  if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s!", &name, &name_len) == FAILURE) {
    RETURN_NULL();
  }
  if (zend_hash_find(&EG(symbol_table), "_SERVER", sizeof("_SERVER"), (void **)&val) == SUCCESS) {
    ht_vars = Z_ARRVAL_PP(val);
    //此处需传入大于name长度+1的值,因为字符串值后面需要''
    if (zend_hash_find(ht_vars, name, name_len+1, (void **)&ret_val) == SUCCESS) {       RETURN_STRING(Z_STRVAL_PP(ret_val), 0);
    }else{
      RETURN_NULL();
    }
  }else{
    RETURN_NULL();
  }
}

define Z_RES_TYPE(zval)            Z_RES(zval)->type
define Z_RES_TYPE_P(zval_p)        Z_RES_TYPE(*zval_p)

8、包装第三方库

define Z_RES_VAL(zval)             Z_RES(zval)->ptr
define Z_RES_VAL_P(zval_p)         Z_RES_VAL(*zval_p)

配置(config.m4)

define Z_REF(zval)                 (zval).value.ref
define Z_REF_P(zval_p)             Z_REF(*(zval_p))

SEARCH_PATH="/usr/local /usr"   #lib搜索的目录
SEARCH_FOR="/include/curl/curl.h" #lib头文件的路径
if test -r $PHP_LIBS/$SEARCH_FOR; then
  LIBS_DIR=$PHP_LIBS
else # search default path list
  AC_MSG_CHECKING([for libs files in default path])
  for i in $SEARCH_PATH ; do
    if test -r $i/$SEARCH_FOR; then
      LIBS_DIR=$i        #搜索到的lib的路径
      AC_MSG_RESULT(found in $i)
    fi
  done
fi
/*验证lib是否存在*/
if test -z "$LIBS_DIR"; then
  AC_MSG_RESULT([not found])
  AC_MSG_ERROR([Please reinstall the libs distribution])
fi
/*编译的时候添加lib的include目录, -I/usr/include*/
PHP_ADD_INCLUDE($LIBS_DIR/include)
LIBNAME=curl      #lib名称 
LIBSYMBOL=curl_version #lib的一个函数,用来PHP_CHECK_LIBRARY验证lib
/*验证lib*/
PHP_CHECK_LIBRARY($LIBNAME,$LIBSYMBOL, 
[
  PHP_ADD_LIBRARY_WITH_PATH($LIBNAME, $LIBS_DIR/$PHP_LIBDIR, LIBS_SHARED_LIBADD) #编译的时候链接lib, -llibcurl
  AC_DEFINE(HAVE_LIBSLIB,1,[ ])
],[
  AC_MSG_ERROR([wrong libs lib version or lib not found])
],[
  -L$LIBS_DIR/$PHP_LIBDIR -lm
]) 
PHP_SUBST(LIBS_SHARED_LIBADD)

define Z_REFVAL(zval)              &Z_REF(zval)->val
define Z_REFVAL_P(zval_p)          Z_REFVAL(*(zval_p))

9、用于返回的宏

define Z_AST(zval)                 (zval).value.ast
define Z_AST_P(zval_p)             Z_AST(*(zval_p))

//这些宏都定义在Zend/zend_API.h文件里
#define RETVAL_RESOURCE(l)              ZVAL_RESOURCE(return_value, l)
#define RETVAL_BOOL(b)                  ZVAL_BOOL(return_value, b)
#define RETVAL_NULL()                   ZVAL_NULL(return_value)
#define RETVAL_LONG(l)                  ZVAL_LONG(return_value, l)
#define RETVAL_DOUBLE(d)                ZVAL_DOUBLE(return_value, d)
#define RETVAL_STRING(s, duplicate)         ZVAL_STRING(return_value, s, duplicate)
#define RETVAL_STRINGL(s, l, duplicate)     ZVAL_STRINGL(return_value, s, l, duplicate)
#define RETVAL_EMPTY_STRING()           ZVAL_EMPTY_STRING(return_value)
#define RETVAL_ZVAL(zv, copy, dtor)     ZVAL_ZVAL(return_value, zv, copy, dtor)
#define RETVAL_FALSE                    ZVAL_BOOL(return_value, 0)
#define RETVAL_TRUE                     ZVAL_BOOL(return_value, 1)
#define RETURN_RESOURCE(l)              { RETVAL_RESOURCE(l); return; }
#define RETURN_BOOL(b)                  { RETVAL_BOOL(b); return; }
#define RETURN_NULL()                   { RETVAL_NULL(); return;}
#define RETURN_LONG(l)                  { RETVAL_LONG(l); return; }
#define RETURN_DOUBLE(d)                { RETVAL_DOUBLE(d); return; }
#define RETURN_STRING(s, duplicate)     { RETVAL_STRING(s, duplicate); return; }
#define RETURN_STRINGL(s, l, duplicate) { RETVAL_STRINGL(s, l, duplicate); return; }
#define RETURN_EMPTY_STRING()           { RETVAL_EMPTY_STRING(); return; }
#define RETURN_ZVAL(zv, copy, dtor)     { RETVAL_ZVAL(zv, copy, dtor); return; }
#define RETURN_FALSE                    { RETVAL_FALSE; return; }
#define RETURN_TRUE                     { RETVAL_TRUE; return; }

define Z_ASTVAL(zval)              (zval).value.ast->ast
define Z_ASTVAL_P(zval_p)          Z_ASTVAL(*(zval_p))

其实,除了这些标量类型,还有很多php语言中的复合类型我们需要在函数中返回,如数组和对象,我们可以通过RETVAL_ZVAL与RETURN_ZVAL来操作它们

define Z_INDIRECT(zval)            (zval).value.zv
define Z_INDIRECT_P(zval_p)        Z_INDIRECT(*(zval_p))

10、hashTable的遍历函数

define Z_CE(zval)                  (zval).value.ce
define Z_CE_P(zval_p)              Z_CE(*(zval_p))

//基于long key的操作函数
zval *v3;
MAKE_STD_ZVAL(v3);
ZVAL_STRING(v3, "value3", 1);
zend_hash_index_update(names, 0, &v3, sizeof(zval *), NULL);//按数字索引键更新HashTable元素的值
zval **v4;
zend_hash_index_find(names, 1, &v4); //按数字索引获取HashTable元素的值
php_printf("v4 : ");
PHPWRITE(Z_STRVAL_PP(v4), Z_STRLEN_PP(v4));
php_printf("n");
ulong idx;
idx = zend_hash_index_exists(names, 10);//按数字索引查找HashTable,如果找到返回 1, 反之则返回 0
zend_hash_index_del(names, 2);    //按数字索引删除HashTable元素
//hashTable的遍历函数
zend_hash_internal_pointer_reset(names); //初始化hash指针
zend_hash_internal_pointer_reset_ex(names, &pos);//初始化hash指针,并付值给pos
zend_hash_get_current_data(names, (void**) &val); //获取当前hash存储值,data should be cast to void**, ie: (void**) &data
zend_hash_get_current_data_ex(names, (void**) &val, &pos) == SUCCESS; //获取当前hash存储值
zend_hash_get_current_key(names, &key, &klen, &index, 0) == HASH_KEY_IS_LONG
zend_hash_get_current_key_ex(names, &key, &klen, &index, 0, &pos) == HASH_KEY_IS_LONG; //读取hashtable当前的KEY,返回值会有两种 HASH_KEY_IS_LONG | HASH_KEY_IS_STRING ,分别对应array("value"),array("key"=>"value")两种hashtable
zend_hash_move_forward(names);
zend_hash_move_forward_ex(names, &pos); //hash指针移至下一位
//HashTable长度
php_printf("%*carray(%d) {n", depth * 2, ' ', zend_hash_num_elements(Z_ARRVAL_P(zv))

define Z_FUNC(zval)                (zval).value.func
define Z_FUNC_P(zval_p)            Z_FUNC(*(zval_p))

一个简单的函数

define Z_PTR(zval)                 (zval).value.ptr
define Z_PTR_P(zval_p)             Z_PTR(*(zval_p))

function hello_array_strings($arr) {
  if (!is_array($arr)) return NULL;
  printf("The array passed contains %d elements ", count($arr));
  foreach($arr as $data) {
    if (is_string($data)) echo "$data ";
  }
}

//===============================================================================

PHP内核实现

php7 用来判断类型和取值

PHP_FUNCTION(hello_array_strings)
{
  zval *arr, **data;
  HashTable *arr_hash;
  HashPosition pointer;
  int array_count;
  if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a", &arr) == FAILURE) {
    RETURN_NULL();
  }
  arr_hash = Z_ARRVAL_P(arr);
  array_count = zend_hash_num_elements(arr_hash);
  php_printf("The array passed contains %d elements ", array_count);
  for(zend_hash_internal_pointer_reset_ex(arr_hash, &pointer); zend_hash_get_current_data_ex(arr_hash, (void**) &data, &pointer) == SUCCESS; zend_hash_move_forward_ex(arr_hash, &pointer)) {
    if (Z_TYPE_PP(data) == IS_STRING) {
      PHPWRITE(Z_STRVAL_PP(data), Z_STRLEN_PP(data));
      php_printf(" ");
    }
  }
  RETURN_TRUE;
}

void display_value(zval zv,zval *zv_p,zval **zv_pp)
{
    if( Z_TYPE(zv) == IS_NULL )
    {
        php_printf("类型是 IS_NULL!n");
    }
     
    if( Z_TYPE_P(zv_p) == IS_LONG )
    {
        php_printf("类型是 IS_LONG,值是:%ld" , Z_LVAL_P(zv_p));
    }
     
    if(Z_TYPE_PP(zv_pp) == IS_DOUBLE )
    {
        php_printf("类型是 IS_DOUBLE,值是:%f" , Z_DVAL_PP(zv_pp) );
    }
}

以上所述就是本文给大家介绍的PHP扩展开发教程,希望大家喜欢。

//================================================================================

PHP7中的定义返回值的宏 Zend/zend_API.h
define RETVAL_BOOL(b)                                  ZVAL_BOOL(return_value, b)
define RETVAL_NULL()                                   ZVAL_NULL(return_value)
define RETVAL_LONG(l)                                  ZVAL_LONG(return_value, l)
define RETVAL_DOUBLE(d)                                ZVAL_DOUBLE(return_value, d)
define RETVAL_STR(s)                                   ZVAL_STR(return_value, s)
define RETVAL_INTERNED_STR(s)                  ZVAL_INTERNED_STR(return_value, s)
define RETVAL_NEW_STR(s)                               ZVAL_NEW_STR(return_value, s)
define RETVAL_STR_COPY(s)                              ZVAL_STR_COPY(return_value, s)
define RETVAL_STRING(s)                                ZVAL_STRING(return_value, s)
define RETVAL_STRINGL(s, l)                    ZVAL_STRINGL(return_value, s, l)
define RETVAL_EMPTY_STRING()                   ZVAL_EMPTY_STRING(return_value)
define RETVAL_RES(r)                                   ZVAL_RES(return_value, r)
define RETVAL_ARR(r)                                   ZVAL_ARR(return_value, r)
define RETVAL_OBJ(r)                                   ZVAL_OBJ(return_value, r)
define RETVAL_ZVAL(zv, copy, dtor)             ZVAL_ZVAL(return_value, zv, copy, dtor)
define RETVAL_FALSE                                    ZVAL_FALSE(return_value)
define RETVAL_TRUE                                     ZVAL_TRUE(return_value)

define RETURN_BOOL(b)                                  { RETVAL_BOOL(b); return; }
define RETURN_NULL()                                   { RETVAL_NULL(); return;}
define RETURN_LONG(l)                                  { RETVAL_LONG(l); return; }
define RETURN_DOUBLE(d)                                { RETVAL_DOUBLE(d); return; }
define RETURN_STR(s)                                   { RETVAL_STR(s); return; }
define RETURN_INTERNED_STR(s)                  { RETVAL_INTERNED_STR(s); return; }
define RETURN_NEW_STR(s)                               { RETVAL_NEW_STR(s); return; }
define RETURN_STR_COPY(s)                              { RETVAL_STR_COPY(s); return; }
define RETURN_STRING(s)                                { RETVAL_STRING(s); return; }
define RETURN_STRINGL(s, l)                    { RETVAL_STRINGL(s, l); return; }
define RETURN_EMPTY_STRING()                   { RETVAL_EMPTY_STRING(); return; }
define RETURN_RES(r)                                   { RETVAL_RES(r); return; }
define RETURN_ARR(r)                                   { RETVAL_ARR(r); return; }
define RETURN_OBJ(r)                                   { RETVAL_OBJ(r); return; }
define RETURN_ZVAL(zv, copy, dtor)             { RETVAL_ZVAL(zv, copy, dtor); return; }
define RETURN_FALSE                                    { RETVAL_FALSE; return; }
define RETURN_TRUE                                     { RETVAL_TRUE; return; }
array_init(return_value);//初始化return_value成数组,此操作完后就可以返回一个空的数组
object_init(return_value);//初始化return_value成Object,此操作完成后返回一个空的对像

//===============================================================================
grep "define ZEND_ACC"  Zend/*.h
内核中提供了定义类以方法的修饰词 Zend/zend_compile.h声明定义

define ZEND_ACC_STATIC         0x01
define ZEND_ACC_ABSTRACT       0x02
define ZEND_ACC_FINAL          0x04
define ZEND_ACC_IMPLEMENTED_ABSTRACT       0x08
define ZEND_ACC_IMPLICIT_ABSTRACT_CLASS    0x10
define ZEND_ACC_EXPLICIT_ABSTRACT_CLASS    0x20
define ZEND_ACC_INTERFACE                  0x40
define ZEND_ACC_TRAIT                      0x80
define ZEND_ACC_ANON_CLASS                 0x100
define ZEND_ACC_ANON_BOUND                 0x200

define ZEND_ACC_PUBLIC     0x100
define ZEND_ACC_PROTECTED  0x200
define ZEND_ACC_PRIVATE    0x400
define ZEND_ACC_PPP_MASK  (ZEND_ACC_PUBLIC | ZEND_ACC_PROTECTED | ZEND_ACC_PRIVATE)
define ZEND_ACC_CHANGED    0x800
define ZEND_ACC_IMPLICIT_PUBLIC    0x1000
define ZEND_ACC_CTOR       0x2000
define ZEND_ACC_DTOR       0x4000
define ZEND_ACC_CLONE      0x8000

//===============================================================================

  1. grep ZEND_ACC  Zend/*.h
    内核中提供了定义类属性的宏  Zend/zend_API.h声明定义

ZEND_API int zend_declare_property_ex(zend_class_entry *ce, zend_string *name, zval *property, int access_type, zend_string *doc_comment);
ZEND_API int zend_declare_property(zend_class_entry *ce, const char *name, size_t name_length, zval *property, int access_type);
ZEND_API int zend_declare_property_null(zend_class_entry *ce, const char *name, size_t name_length, int access_type);
ZEND_API int zend_declare_property_bool(zend_class_entry *ce, const char *name, size_t name_length, zend_long value, int access_type);
ZEND_API int zend_declare_property_long(zend_class_entry *ce, const char *name, size_t name_length, zend_long value, int access_type);
ZEND_API int zend_declare_property_double(zend_class_entry *ce, const char *name, size_t name_length, double value, int access_type);
ZEND_API int zend_declare_property_string(zend_class_entry *ce, const char *name, size_t name_length, const char *value, int access_type);
ZEND_API int zend_declare_property_stringl(zend_class_entry *ce, const char *name, size_t name_length, const char *value, size_t value_len, int access_type);

更新类中的数据成员 Zend/zend_API.h声明定义

ZEND_API void zend_update_property_ex(zend_class_entry *scope, zval *object, zend_string *name, zval *value);
ZEND_API void zend_update_property(zend_class_entry *scope, zval *object, const char *name, size_t name_length, zval *value);
ZEND_API void zend_update_property_null(zend_class_entry *scope, zval *object, const char *name, size_t name_length);
ZEND_API void zend_update_property_bool(zend_class_entry *scope, zval *object, const char *name, size_t name_length, zend_long value);
ZEND_API void zend_update_property_long(zend_class_entry *scope, zval *object, const char *name, size_t name_length, zend_long value);
ZEND_API void zend_update_property_double(zend_class_entry *scope, zval *object, const char *name, size_t name_length, double value);
ZEND_API void zend_update_property_str(zend_class_entry *scope, zval *object, const char *name, size_t name_length, zend_string *value);
ZEND_API void zend_update_property_string(zend_class_entry *scope, zval *object, const char *name, size_t name_length, const char *value);
ZEND_API void zend_update_property_stringl(zend_class_entry *scope, zval *object, const char *name, size_t name_length, const char *value, size_t value_length);

grep "zend_read_"  ../../Zend/*.h
读取类中的数据成员 在Zend/zend_API.h声明定义

ZEND_API zval *zend_read_property(zend_class_entry *scope, zval *object, const char *name, size_t name_length, zend_bool silent, zval *rv);

//===============================================================================

  1. grep "zend_declare_class_constant"  Zend/*.h
    创建类中的常量的方法在Zend/zend_API.h声明定义

ZEND_API int zend_declare_class_constant(zend_class_entry *ce, const char *name, size_t name_length, zval *value);
ZEND_API int zend_declare_class_constant_null(zend_class_entry *ce, const char *name, size_t name_length);
ZEND_API int zend_declare_class_constant_long(zend_class_entry *ce, const char *name, size_t name_length, zend_long value);
ZEND_API int zend_declare_class_constant_bool(zend_class_entry *ce, const char *name, size_t name_length, zend_bool value);
ZEND_API int zend_declare_class_constant_double(zend_class_entry *ce, const char *name, size_t name_length, double value);
ZEND_API int zend_declare_class_constant_stringl(zend_class_entry *ce, const char *name, size_t name_length, const char *value, size_t value_length);
ZEND_API int zend_declare_class_constant_string(zend_class_entry *ce, const char *name, size_t name_length, const char *value);

更新类中的常量数据成员 Zend/zend_API.h声明定义
ZEND_API int zend_update_class_constants(zend_class_entry *class_type);

//=================================================================================

  1. grep "zend_update_static_"  ../../Zend/*.h
    更新类中的静态数据成员 在Zend/zend_API.

ZEND_API int zend_update_static_property(zend_class_entry *scope, const char *name, size_t name_length, zval *value);
ZEND_API int zend_update_static_property_null(zend_class_entry *scope, const char *name, size_t name_length);
ZEND_API int zend_update_static_property_bool(zend_class_entry *scope, const char *name, size_t name_length, zend_long value);
ZEND_API int zend_update_static_property_long(zend_class_entry *scope, const char *name, size_t name_length, zend_long value);
ZEND_API int zend_update_static_property_double(zend_class_entry *scope, const char *name, size_t name_length, double value);
ZEND_API int zend_update_static_property_string(zend_class_entry *scope, const char *name, size_t name_length, const char *value);
ZEND_API int zend_update_static_property_stringl(zend_class_entry *scope, const char *name, size_t name_length, const char *value, size_t value_length);

grep "zend_read_"  ../../Zend/*.h
读取类中的数据成员 在Zend/zend_API.h声明定义

ZEND_API zval *zend_read_static_property(zend_class_entry *scope, const char *name, size_t name_length, zend_bool silent);

```

  • 请尊重本人劳动成功,可以随意转载但保留以下信息
  • 作者:岁月经年
  • 时间:2016年04月

![avatar]()

本文由10bet手机官网发布于web前端,转载请注明出处:PHP扩展开发教程,函数传入数组

上一篇:没有了 下一篇:php数组排序之多维数组与一维数组,php对二维数组进行相关操作10bet手机官网
猜你喜欢
热门排行
精彩图文