PHP扩展说明

技术文档网 2021-04-16

PHP扩展是php扩展的功能。常见的扩展有哪些呢?

1,mysql(独立函数)

$con = mysql_connect("localhost","peter","abc123");

2,redis(类)

$redis = new Redis();
$redis->connect('127.0.0.1', 6379);

3,DES加密等

一般扩展的安装步奏

Linux 扩展编译安装部署步奏(入门)

$ /$path/phpize
$ ./configure + php-cofnig
$ make && make install
$ 添加生成的 ext.so 到 php.ini

不同扩展开发测试流程结构

  1. config.m4为配置定义文件,用来读取编译命令。
  2. myext.so为编译后生成的二进制文件。
  3. 代码在myext.c中,编译完成并且加入到php.ini后。
  4. 运行 $ php test.php

以下是ext_skel可以帮你生成的基本框架,本节课主要是以ext_skel生成的目录结构解析。

  1. config.m4
  2. php_{extname}.h
  3. {extname}.c

config.m4 主要包含哪些内容?

扩展没有引用外部组件, 则使用enable,否则用with。以下说明都是采用enable的模式,使用with的扩展比如mysql等等

dnl $Id$
dnl config.m4 for extension myext

dnl Comments in this file start with the string 'dnl'.
dnl Remove where necessary. This file will not work
dnl without editing.

dnl If your extension references something external, use with:

dnl PHP_ARG_WITH(myext, for myext support,
dnl Make sure that the comment is aligned:
dnl [  --with-myext             Include myext support])

dnl Otherwise use enable:

PHP_ARG_ENABLE(myext, whether to enable myext support,
Make sure that the comment is aligned:
[  --enable-myext           Enable myext support])

if test "$PHP_MYEXT" != "no"; then
  dnl Write more examples of tests here...

  dnl # --with-myext -> check with-path
  dnl SEARCH_PATH="/usr/local /usr"     # you might want to change this
  dnl SEARCH_FOR="/include/myext.h"  # you most likely want to change this
  dnl if test -r $PHP_MYEXT/$SEARCH_FOR; then # path given as parameter
  dnl   MYEXT_DIR=$PHP_MYEXT
  dnl else # search default path list
  dnl   AC_MSG_CHECKING([for myext files in default path])
  dnl   for i in $SEARCH_PATH ; do
  dnl     if test -r $i/$SEARCH_FOR; then
  dnl       MYEXT_DIR=$i
  dnl       AC_MSG_RESULT(found in $i)
  dnl     fi
  dnl   done
  dnl fi
  dnl
  dnl if test -z "$MYEXT_DIR"; then
  dnl   AC_MSG_RESULT([not found])
  dnl   AC_MSG_ERROR([Please reinstall the myext distribution])
  dnl fi

  dnl # --with-myext -> add include path
  dnl PHP_ADD_INCLUDE($MYEXT_DIR/include)

  dnl # --with-myext -> check for lib and symbol presence
  dnl LIBNAME=myext # you may want to change this
  dnl LIBSYMBOL=myext # you most likely want to change this

  dnl PHP_CHECK_LIBRARY($LIBNAME,$LIBSYMBOL,
  dnl [
  dnl   PHP_ADD_LIBRARY_WITH_PATH($LIBNAME, $MYEXT_DIR/lib, MYEXT_SHARED_LIBADD)
  dnl   AC_DEFINE(HAVE_MYEXTLIB,1,[ ])
  dnl ],[
  dnl   AC_MSG_ERROR([wrong myext lib version or lib not found])
  dnl ],[
  dnl   -L$MYEXT_DIR/lib -lm
  dnl ])
  dnl
  dnl PHP_SUBST(MYEXT_SHARED_LIBADD)

  PHP_NEW_EXTENSION(myext, myext.c, $ext_shared)
fi

已上文件内容包含了那些语义?

AC_MSG_CHECKING(message)
在执行 configure 命令时输出“checking <message>”等信息。

AC_MSG_RESULT(value)
取得 AC_MSG_CHECKING 的执行结果,一般情况下 value 应为 yes 或 no。

AC_MSG_ERROR(message)
在执行 configure 命令时输出一条错误消息 message 并中止脚本的执行。

AC_DEFINE(name,value,description)
向 php_config.h 添加一行定义:#define name value // description (这对模块的条件编译很有用。)

AC_ADD_INCLUDE(path)
添加一条编译器的包含路径,比如用于模块需要为头文件添加搜索路径。

AC_ADD_LIBRARY_WITH_PATH(libraryname,librarypath)
指定一个库的连接路径。

AC_ARG_WITH(modulename,description,unconditionaltest,conditionaltest)
这是一款比较强大的宏,用于将模块的描述 description 添加到“configure –help”命令的输出里面。PHP 会检查当前执行的 configure 脚本里面有没有–with-<modulename> 这个选项。 如果有则执行 unconditionaltest 语句(比如 –with-myext=yes 等), 此时,选项的值会被包含在 $withval 变量里面。否则就执行 conditionaltest 语句。

PHP_NEW_EXTENSION(myredis, myredis.c library.c, $ext_shared)

{extname}.c核心代码文件部分

zend_module_entry

zend_module_entry myext_module_entry = {
 #if ZEND_MODULE_API_NO >= 20010901
         STANDARD_MODULE_HEADER,
 #endif
         "myext",
         NULL,   /*const struct _zend_function_entry *functions*/
         PHP_MINIT(myext),
         PHP_MSHUTDOWN(myext),
         PHP_RINIT(myext),               /* Replace with NULL if there's nothing to do at request start */
         PHP_RSHUTDOWN(myext),   /* Replace with NULL if there's nothing to do at request end */
         PHP_MINFO(myext),
 #if ZEND_MODULE_API_NO >= 20010901
         PHP_MYEXT_VERSION,
 #endif
         STANDARD_MODULE_PROPERTIES
};

打开“php_myext.h”,会看到里面有怎么一行:

extern zend_module_entry myext_module_entry;

那么该PHP Extension的源码结构是如何的呢?(Zend/zend_modules.h)

typedef struct _zend_module_entry zend_module_entry;

struct _zend_module_entry {
    unsigned short size;
    unsigned int zend_api;
    unsigned char zend_debug;
    unsigned char zts;
    const struct _zend_ini_entry *ini_entry;
    const struct _zend_module_dep *deps;
    const char *name;
    const struct _zend_function_entry *functions;
    int (*module_startup_func)(INIT_FUNC_ARGS);
    int (*module_shutdown_func)(SHUTDOWN_FUNC_ARGS);
    int (*request_startup_func)(INIT_FUNC_ARGS);
    int (*request_shutdown_func)(SHUTDOWN_FUNC_ARGS);
    void (*info_func)(ZEND_MODULE_INFO_FUNC_ARGS);
    const char *version;
    size_t globals_size;
#ifdef ZTS
    ts_rsrc_id* globals_id_ptr;
#else
    void* globals_ptr;
#endif
    void (*globals_ctor)(void *global TSRMLS_DC);
    void (*globals_dtor)(void *global TSRMLS_DC);
    int (*post_deactivate_func)(void);
    int module_started;
    unsigned char type;
    void *handle;
    int module_number;
    char *build_id;
};

上面生成的结构体中和已上源码结构体是匹配上的。其中有几个指针函数(module_startup_func,module_shutdown_func,request_startup_func,request_shutdown_func),这四个函数会在相应时机被调用,分别是“扩展模块加载时”、“扩展模块卸载时”、“每个请求开始时”和“每个请求结束时”。这四个函数可以看成是一种拦截机制,主要用于相应时机的资源分配、释放等相关操作。 (后面再说)

独立函数demo (自行尝试)

ZEND_FUNCTION(say_hello)
{
    php_printf("Hello World!");
}

static zend_function_entry say_hello_functions[] = {
    ZEND_FE(say_hello, NULL)
    {
        NULL,
        NULL,
        NULL
    }
};

zend_module_entry gglinux_module_entry = {
#if ZEND_MODULE_API_NO >= 20010901
     STANDARD_MODULE_HEADER,
#endif
    "say_hello",
    say_hello_functions, /* Functions */
    NULL, /* MINIT */
    NULL, /* MSHUTDOWN */
    NULL, /* RINIT */
    NULL, /* RSHUTDOWN */
    NULL, /* MINFO */
#if ZEND_MODULE_API_NO >= 20010901
    "2.1",
#endif
    STANDARD_MODULE_PROPERTIES
};

返回值如何返回

PHP内核定义

#define INTERNAL_FUNCTION_PARAMETERS int ht, zval *return_value, zval **return_value_ptr, zval *this_ptr, int return_value_used TSRMLS_DC

以上定义说明

int ht
zval *return_value,我们在函数内部修改这个指针,函数执行完成后,内核将把这个指针指向的zval返回给用户端的函数调用者。
zval **return_value_ptr,
zval *this_ptr,如果此函数是一个类的方法,那么这个指针的含义和PHP语言中$this变量差不多。
int return_value_used,代表用户端在调用此函数时有没有使用到它的返回值。

以上return_value这个指针用来保存用户返回的结果值。那么扩展中是如何写的呢?

ZVAL_LONG(return_value, 42);

宏展开后

Z_TYPE_P(return_value) = IS_LONG;
Z_LVAL_P(return_value) = 42;

//更彻底的讲,应该是这样的:
return_value->type = IS_LONG;
return_value->value.lval = 42;

return_value有关的宏

return_value如此重要,内核肯定早已经为它准备了大量的宏,来简化我们的操作,提高程序的质量。 在前几章我们接触的宏大多都是以ZVAL_开头的,而接下来我们要介绍的宏的名字是:RETVAL。 再回到上面的那个例子,我们用RETVAL来重写一下:

RETVAL_LONG(42);
// 下面是其他的例子
/*
//这些宏都定义在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; }
*/

还有一种特殊的情况,如果返回值未被使用呢? 我们来看看这种情况。

<?php
function sample_array_range() {
    $ret = array();
    for($i = 0; $i < 1000; $i++) {
        $ret[] = $i;
    }
    return $ret;
}
sample_array_range();

上面这种情况运行了一下 但是并没有将数据返回给调用者,那么就可以使用变量return_value_used来减少内存使用。当然这个例子比较极端。

ZEND_FUNCTION(sample_array_range)
{
    if (return_value_used) {
        int i;

        //把返回值初始化成一个PHP语言中的数组
        array_init(return_value);
        for(i = 0; i < 1000; i++)
        {
            //向retrun_value里不断的添加新元素,值为i
            add_next_index_long(return_value, i);
        }
        return;
    }
    else
    {
        //抛出一个E_NOTICE级错误
        php_error_docref(NULL TSRMLS_CC, E_NOTICE,"猫了个咪的,我就知道你没用我的劳动成果!");
        RETURN_NULL();
    }
}

还有其他引用返回等等,感兴趣的可以自行研究一下。扩展函数的返回值已经简单的说完了,那么输入参数如何传入呢?

参数输入获取

那我们举个简单例子, PHP参数输入是通过zend api的zend_parse_parameters函数获取的。

ZEND_FUNCTION(sample_getlong) {

    long foo;
    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,"l", &foo) == FAILURE)
    {
        RETURN_NULL();
    }
    php_printf("The integer value of the parameter is: %ld\n", foo);
    RETURN_TRUE;
}

long, string, resource等等都有不同的获取标识符号。string需要两个字段接受,一个是字符串,一个是长度。

在了解完函数的输入参数和返回结果之后,那么如果定义一个类对象呢?

类对象的实现

下面是一个redis demo的类对象的编写代码。我们来介绍一下核心代码实现。

INIT_CLASS_ENTRY(redis_class_entry, "Myredis", myredis_functions);  //注册类
redis_ce = zend_register_internal_class(&redis_class_entry TSRMLS_CC);

1,首先我们看一下INIT_CLASS_ENTRY这个宏的具体展开式实现

#define INIT_CLASS_ENTRY(class_container, class_name, functions)    INIT_OVERLOADER_CLASS_ENTRY(class_container, class_name, functions, NULL, NULL, NULL)
#define INIT_OVERLOADER_CLASS_ENTRY(class_container, class_name, functions, handle_fcall, handle_propget, handle_propset) \
    INIT_OVERLOADER_CLASS_ENTRY_EX(class_container, class_name, sizeof(class_name)-1,functions, handle_fcall, handle_propget, handle_propset)
#define INIT_OVERLOADER_CLASS_ENTRY_EX(class_container, class_name, class_name_len, functions, handle_fcall, handle_propget, handle_propset)
{
    const char * cl_name = class_name;
    int _len = class_name_len;
    class_container.name = zend_new_interned_string(cl_name, _len+1, 0 TSRMLS_CC);
    if(class_container.name == cl_name){
        //??
        class_container.name = zend_strndup(cl_name, _len);
    }
    class_container.name_length = _len;
    INIT_CLASS_ENTRY_INIT_METHODS(class_container, functions, handle_fcall, handle_propget, handle_propset)
}
#define INIT_CLASS_ENTRY_INIT_METHODS(class_container, functions, handle_fcall, handle_propget, handle_propset)
{
        class_container.builtin_functions = functions;
        class_container.constructor = NULL;
        class_container.destructor = NULL;
        class_container.clone = NULL;
        class_container.serialize = NULL;
        class_container.unserialize = NULL;
        class_container.create_object = NULL;
        class_container.interface_gets_implemented = NULL;
        class_container.__call = handle_fcall;
        class_container.__tostring = NULL;
        class_container.__get = handle_propget;
        class_container.__set = handle_propset;
        class_container.__unset = NULL;
        class_container.__isset = NULL;
        class_container.serialize_func = NULL;
        class_container.unserialize_func = NULL;
        class_container.serialize = NULL;
        class_container.unserialize = NULL;
        class_container.parent = NULL;
        class_container.num_interfaces = 0;
        class_container.interfaces = NULL;
        class_container.get_iterator = NULL;
        class_container.iterator_funcs.funcs = NULL;
        class_container.module = NULL;
}
struct _zend_class_entry {
    char type;     // „类型:ZEND_INTERNAL_CLASS / ZEND_USER_CLASS
    char *name;// 类名称
    zend_uint name_length;                  // 即sizeof(name) - 1
    structͺ_zend_class_entry *parent; // 继承的父类
    intͺrefcount;  // 引用数
    zend_bool constants_updated;

    zend_uint ce_flags; // ZEND_ACC_IMPLICIT_ABSTRACT_CLASS: 类存在abstract方法
    // ZEND_ACC_EXPLICIT_ABSTRACT_CLASS: 在类名称前加abstract关键字
     // ZEND_ACC_FINAL_CLASS
    // ZEND_ACC_INTERFACE
    HashTable function_table;      // ’方法
    HashTable default_properties;          // 默认属性
    HashTable properties_info;     // 属性信息
    HashTable default_static_members;// „类本身所具有的静态变量
    HashTable *static_members; // type == ZEND_USER_CLASS时,取&default_static_members;
    // type == ZEND_INTERAL_CLASS时,设ŒNULL
    HashTable constants_table;     // 常量
    struct _zend_function_entry *builtin_functions;// 方法定义入口


    union _zend_function *constructor;
    union _zend_function *destructor;
    union _zend_function *clone;


    /* 魔术方法 */
    union _zend_function *__get;
    union _zend_function *__set;
    union _zend_function *__unset;
    union _zend_function *__isset;
    union _zend_function *__call;
    union _zend_function *__tostring;
    union _zend_function *serialize_func;
    union _zend_function *unserialize_func;
    zend_class_iterator_funcs iterator_funcs;// 迭代

    /* 类句柄 */
    zend_object_value (*create_object)(zend_class_entry *class_type TSRMLS_DC);
    zend_object_iterator *(*get_iterator)(zend_class_entry *ce, zval *object,
        intby_ref TSRMLS_DC);

    /* 类声明的接口 */
    int(*interface_gets_implemented)(zend_class_entry *iface,
            zend_class_entry *class_type TSRMLS_DC);


    /* 序列化回调函数指针 */
    int(*serialize)(zval *object unsignedchar**buffer, zend_uint *buf_len,
             zend_serialize_data *data TSRMLS_DC);
    int(*unserialize)(zval **object, zend_class_entry *ce,
constunsignedchar*buf,
            zend_uint buf_len, zend_unserialize_data *data TSRMLS_DC);


    zend_class_entry **interfaces;  // 类实现的接口
    zend_uint num_interfaces;   // 类实现的接口数

    char *filename; // 类的存放文件地址 绝对地址
    zend_uint line_start;   // 类定义的开始行 ˆ
    zend_uint line_end; // 类定义的结束行
    char *doc_comment;
    zend_uint doc_comment_len;


    struct _zend_module_entry *module; // 类所在的模块入口EG(current_module)
};

上面的代码段执行了其实就是zend_class_entry对象的初始化。

static zend_class_entry *do_register_internal_class(zend_class_entry *orig_class_entry, zend_uint ce_flags TSRMLS_DC) /* {{{ */
{
   zend_class_entry *class_entry = malloc(sizeof(zend_class_entry));
   char *lowercase_name = emalloc(orig_class_entry->name_length + 1);
   *class_entry = *orig_class_entry;

   class_entry->type = ZEND_INTERNAL_CLASS;
   zend_initialize_class_data(class_entry, 0 TSRMLS_CC);
   class_entry->ce_flags = ce_flags;
   class_entry->info.internal.module = EG(current_module);

   if (class_entry->info.internal.builtin_functions) {
      zend_register_functions(class_entry, class_entry->info.internal.builtin_functions, &class_entry->function_table, MODULE_PERSISTENT TSRMLS_CC);
   }

   zend_str_tolower_copy(lowercase_name, orig_class_entry->name, class_entry->name_length);
   lowercase_name = (char*)zend_new_interned_string(lowercase_name, class_entry->name_length + 1, 1 TSRMLS_CC);
   if (IS_INTERNED(lowercase_name)) {
      //这个是如果key为空的话那么就直接计算hashKey的值的。
      zend_hash_quick_update(CG(class_table), lowercase_name, class_entry->name_length+1, INTERNED_HASH(lowercase_name), &class_entry, sizeof(zend_class_entry *), NULL);
   } else {
      //根据key计算hashKey然后如果为空则返回错误。
      zend_hash_update(CG(class_table), lowercase_name, class_entry->name_length+1, &class_entry, sizeof(zend_class_entry *), NULL);
   }
   str_efree(lowercase_name);
   return class_entry;
}

该函数主要用于类对象的在PHP内存存储

那么说完PHP类对象创建的过程后,那我们开始说这种创建的类对象的自定义函数是怎么绑定关联的。

1,首先我们先介绍几种常见的函数宏。

普通函数

PHP_FUNCTION(func_name)
等价于void {func_name}(INTERNAL_FUNCTION_PARAMETERS)

类函数

PHP_METHOD(class_name, func_name)
等价于zim_{class_name}_{func_name}
PHP_ME(class_name, func_name, arg_info, flags)
等价于 {class_name, zim_{class_name} _{func_name}, arg_info,
(zend_uint)(sizeof(arg_info)/sizeof(struct _zend_arg_info) - 1),flags},

下面是一个简单的关联类函数的demo片段。

const zend_function_entry myext_functions[] = {
         PHP_ME(Myext, __construct, NULL, ZEND_ACC_CTOR | ZEND_ACC_PUBLIC)
         PHP_ME(Myext, __destruct, NULL, ZEND_ACC_DTOR | ZEND_ACC_PUBLIC)
         PHP_ME(Myext, close, NULL, ZEND_ACC_PUBLIC)
         PHP_ME(Myext, getFile, NULL, ZEND_ACC_PUBLIC)
         PHP_ME(Myext, getHttp, NULL, ZEND_ACC_PUBLIC)
         {NULL, NULL, NULL}
};
PHP_MINIT_FUNCTION(myext)
{
      zend_class_entry ext_class_entry;
      /* ext class */
      INIT_CLASS_ENTRY(ext_class_entry, "Myext", myext_functions);
      ext_ce = zend_register_internal_class(&ext_class_entry TSRMLS_CC);
      return SUCCESS;
}
PHP_METHOD(Myext, getHttp){
     php_stream *stream;
     char inbuf[1024];
     zval *object;
     char *host, *path, *errstr = NULL;
     int host_len, path_len, implicit_tcp = 1, errcode = 0;
     long port;
     int options = ENFORCE_SAFE_MODE;
     char *content = "";
     int flags = STREAM_XPORT_CLIENT | STREAM_XPORT_CONNECT;
     if(zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Oss",
                                     &object, ext_ce, &host, &host_len, &path, &path_len) == FAILURE)
     {
         RETURN_FALSE;
     }

     stream = php_stream_xport_create(host, host_len,
             options, flags,
             NULL, NULL, NULL, &errstr, &errcode);
     if (errstr) {
         php_error_docref(NULL TSRMLS_CC, E_WARNING, "[%d] %s",
                 errcode, errstr);
         efree(errstr);
     }
     if (!stream) {
         RETURN_FALSE;
     }

     char getContent[4096];
     sprintf(getContent, "GET %s HTTP/1.0\r\nHost: %s\r\nUser-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3\r\nConnection:close\r\n\r\n" ,path,host);
         php_stream_write(stream, getContent, sizeof(getContent));
         while(php_stream_gets(stream, inbuf, sizeof(inbuf)) != NULL) {
         content = mystrcat(content, inbuf);
     }
     RETURN_STRING(content, 1);
}

那么已上就是常见的独立函数开发,已经类对象的开发过程。

基础理解的常用结构体如下

_zval_struct
zend_class_entry
zend_function_entry
HashTable

插一下PHP弱类型变量数据结构实现。 简单说一下PHP内存回收机制。

struct _zval_struct {
    zvalue_value value;     /* value */
    zend_uint refcount__gc;  /* variable ref count */
    zend_uchar type;          /* active type */
    zend_uchar is_ref__gc;    /* if it is a ref variable */
};
typedef struct _zval_struct zval;
typedef union _zvalue_value {
    long lval;                  /* long value */
    double dval;                /* double value */
    struct {                    /* string */
        char *val;
        int len;
    } str;
    HashTable *ht;              /* hash table value,used for array */
    zend_object_value obj;      /* object */
} zvalue_value;

PHP内存管理机制是如何的呢? 简单的聊聊...

PHP全局变量是如何实现的? 这个就不展开了... 有兴趣的自己了解一下。常用访问变量对象信息的宏...

EG()、这个宏可以用来访问符号表,函数,资源信息和常量

CG() 用来访问核心全局变量

PG() PHP全局变量。我们知道php.ini会映射一个或者多个PHP全局结构。举几个使用这个宏的例子:PG(register_globals), PG(safe_mode), PG(memory_limit)

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

PHP HashTable机制

旧版:http://www.cnblogs.com/ohmygirl/p/internal-3.html

新版: http://blog.csdn.net/xiaolei1982/article/details/52292866

/* zend_hash.c zend_hash.h */
ZEND_API ulong zend_hash_func(const char *arKey, uint nKeyLength)
ZEND_API ulong zend_get_hash_value(const char *arKey, uint nKeyLength)
ZEND_API int _zend_hash_init(HashTable *ht, uint nSize, hash_func_t pHashFunction, dtor_func_t pDestructor, zend_bool persistent ZEND_FILE_LINE_DC)
 ZEND_API void zend_hash_set_apply_protection(HashTable *ht, zend_bool bApplyProtection)
ZEND_API int _zend_hash_add_or_update(HashTable *ht, const char *arKey, uint nKeyLength, void *pData, uint nDataSize, void **pDest, int flag ZEND_FILE_LINE_DC)
ZEND_API int _zend_hash_quick_add_or_update(HashTable *ht, const char *arKey, uint nKeyLength, ulong h, void *pData, uint nDataSize, void **pDest, int flag ZEND_FILE_LINE_DC)
ZEND_API int _zend_hash_index_update_or_next_insert(HashTable *ht, ulong h, void *pData, uint nDataSize, void **pDest, int flag ZEND_FILE_LINE_DC)
ZEND_API int zend_hash_rehash(HashTable *ht)
static int zend_hash_do_resize(HashTable *ht)
ZEND_API int zend_hash_del_key_or_index(HashTable *ht, const char *arKey, uint nKeyLength, ulong h, int flag)
ZEND_API void zend_hash_destroy(HashTable *ht)
ZEND_API void zend_hash_clean(HashTable *ht)
static Bucket *zend_hash_apply_deleter(HashTable *ht, Bucket *p)
ZEND_API void zend_hash_graceful_destroy(HashTable *ht)
ZEND_API void zend_hash_graceful_reverse_destroy(HashTable *ht)
ZEND_API void zend_hash_apply(HashTable *ht, apply_func_t apply_func TSRMLS_DC)
ZEND_API void zend_hash_apply_with_argument(HashTable *ht, apply_func_arg_t apply_func, void *argument TSRMLS_DC)
ZEND_API void zend_hash_apply_with_arguments(HashTable *ht TSRMLS_DC, apply_func_args_t apply_func, int num_args, …)
ZEND_API void zend_hash_reverse_apply(HashTable *ht, apply_func_t apply_func TSRMLS_DC)
ZEND_API void zend_hash_copy(HashTable *target, HashTable *source, copy_ctor_func_t pCopyConstructor, void *tmp, uint size)
ZEND_API void _zend_hash_merge(HashTable *target, HashTable *source, copy_ctor_func_t pCopyConstructor, void *tmp, uint size, int overwrite ZEND_FILE_LINE_DC)
static zend_bool zend_hash_replace_checker_wrapper(HashTable *target, void *source_data, Bucket *p, void *pParam, merge_checker_func_t merge_checker_func)
ZEND_API void zend_hash_merge_ex(HashTable *target, HashTable *source, copy_ctor_func_t pCopyConstructor, uint size, merge_checker_func_t pMergeSource, void *pParam)
ZEND_API int zend_hash_find(const HashTable *ht, const char *arKey, uint nKeyLength, void **pData)
ZEND_API int zend_hash_quick_find(const HashTable *ht, const char *arKey, uint nKeyLength, ulong h, void **pData)
ZEND_API int zend_hash_exists(const HashTable *ht, const char *arKey, uint nKeyLength)
ZEND_API int zend_hash_quick_exists(const HashTable *ht, const char *arKey, uint nKeyLength, ulong h)
ZEND_API int zend_hash_index_find(const HashTable *ht, ulong h, void **pData)
ZEND_API int zend_hash_index_exists(const HashTable *ht, ulong h)
ZEND_API int zend_hash_num_elements(const HashTable *ht)
ZEND_API int zend_hash_get_pointer(const HashTable *ht, HashPointer *ptr)
ZEND_API int zend_hash_set_pointer(HashTable *ht, const HashPointer *ptr)
ZEND_API void zend_hash_internal_pointer_reset_ex(HashTable *ht, HashPosition *pos)
ZEND_API void zend_hash_internal_pointer_end_ex(HashTable *ht, HashPosition *pos)
ZEND_API int zend_hash_move_forward_ex(HashTable *ht, HashPosition *pos)
ZEND_API int zend_hash_move_backwards_ex(HashTable *ht, HashPosition *pos)
ZEND_API int zend_hash_get_current_key_ex(const HashTable *ht, char **str_index, uint *str_length, ulong *num_index, zend_bool duplicate, HashPosition *pos)
ZEND_API int zend_hash_get_current_key_type_ex(HashTable *ht, HashPosition *pos)
ZEND_API int zend_hash_get_current_data_ex(HashTable *ht, void **pData, HashPosition *pos)
ZEND_API int zend_hash_update_current_key_ex(HashTable *ht, int key_type, const char *str_index, uint str_length, ulong num_index, int mode, HashPosition *pos)
ZEND_API int zend_hash_sort(HashTable *ht, sort_func_t sort_func, compare_func_t compar, int renumber TSRMLS_DC)
ZEND_API int zend_hash_compare(HashTable *ht1, HashTable *ht2, compare_func_t compar, zend_bool ordered TSRMLS_DC)
ZEND_API int zend_hash_minmax(const HashTable *ht, compare_func_t compar, int flag, void **pData TSRMLS_DC)
ZEND_API ulong zend_hash_next_free_element(const HashTable *ht)
void zend_hash_display_pListTail(const HashTable *ht)
void zend_hash_display(const HashTable *ht)

自定义DEMO (网上看到的DEMO,可以自行体验hashTable的API用法, 主要是在一些类对象的获取该对象的时候可能会使用。)

ZEND_FUNCTION(gglinux_test_hashtable)
{
    HashTable *test_ht;
    int ht_len = 10;
    test_ht = test_hashtable_create(test_ht,ht_len);
    test_hashtable_scan(test_ht);
    //毁尸灭迹
    zend_hash_destroy(test_ht);

    FREE_HASHTABLE(test_ht);
    return SUCCESS;


}

/*
   新建哈希表
*/
void test_hashtable_create(HashTable *ht, int hashtable_len)
{
        //分配内存
    ALLOC_HASHTABLE(ht);

    //初始化
    if (zend_hash_init(ht, hashtable_len, NULL,ZVAL_PTR_DTOR, 0) == FAILURE) {
        FREE_HASHTABLE(ht);
        return FAILURE;
    }
    int i;

    for (i = 0; i < hashtable_len; i++)
    {
        zval *value;
        MAKE_STD_ZVAL(value);
        ZVAL_LONG(value, i);
        i++;
        //添加数据(不需要索引值参数)
        if(zend_hash_next_index_insert(ht, (void **) &value, sizeof(zval *), NULL) == FAILURE) {
            //更新引用计数
            zval_ptr_dtor(&value);
        }
    }
    return ht;
}

/*
    遍历哈希表 回调方法
*/
int test_print_zval(zval **val TSRMLS_DC)
{
    //重新copy一个zval,防止破坏原数据
    zval tmpcopy = **val;
    zval_copy_ctor(&tmpcopy);

    //转换为字符串
    INIT_PZVAL(&tmpcopy);
    convert_to_string(&tmpcopy);

    //开始输出
    php_printf("The value is: ");
    PHPWRITE(Z_STRVAL(tmpcopy), Z_STRLEN(tmpcopy));
    php_printf("\n");

    //毁尸灭迹
    zval_dtor(&tmpcopy);

    //返回,继续遍历下一个
    return ZEND_HASH_APPLY_KEEP;
}

/*
    哈希表遍历
*/
void test_hashtable_scan(HashTable *ht)
{
    zend_hash_apply(ht, test_print_zval TSRMLS_CC);
}

PHP Array 常用方法举例

{
    zval *subarray;
    array_init(return_value);

    // ["life"]=> int(42)
    add_assoc_string(return_value, "name", "gglinux",1);
    // [123]=> bool(true)
    add_index_bool(return_value, 123, 1);
    //[124]=> float(7.77)
    add_next_index_double(return_value, 7.77);
    // [125]=> string(3) "Foo"
    add_next_index_string(return_value, "Foo", 1);

    //[126]=> string(3) "Bar"
    //PHP内存管理API都在原来的C++函数前面加了一个“e”,这样的内存分配是被PHP内核管理的。这里就不过多展开了。
    add_next_index_string(return_value, estrdup("Bar"), 0);

    //子数组
    MAKE_STD_ZVAL(subarray);
    array_init(subarray);

    //添加值
    add_next_index_long(subarray, 1);
    add_index_bool(subarray, 123, 1);

    //添加到父串中
    add_index_zval(return_value, 444, subarray);
}

那么PHP中资源对象是怎么回事呢,这里我就不在进行代码说明了,我们直接进入PHP扩展的调试方法的说明

PHP扩展如何调试?

1,具体调试方法

1.1 如果查询需要断点的函数点。

nm /usr/local/php/bin/php  |grep fopen

1.2 进入调试模式

gdb php

1.3 设置一个函数断点。

break php_if_fopen

1.4 运行需要调试的程序。

run /home/xuxiaoyu/test.php

1.5 查看调试过程截图

1.6 查看调试变量值。

2,PHP扩展调试去查看实现源代码。

PHP_NAMED_FUNCTION(php_if_fopen)
{
    char *filename, *mode;
    int filename_len, mode_len;
    zend_bool use_include_path = 0;
    zval *zcontext = NULL;
    php_stream *stream;
    php_stream_context *context = NULL;

    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ps|br", &filename, &filename_len, &mode, &mode_len, &use_include_path, &zcontext) == FAILURE) {
        RETURN_FALSE;
    }

    context = php_stream_context_from_zval(zcontext, 0);

    stream = php_stream_open_wrapper_ex(filename, mode, (use_include_path ? USE_PATH : 0) | REPORT_ERRORS, NULL, context);

    if (stream == NULL) {
        RETURN_FALSE;
    }

    php_stream_to_zval(stream, return_value);
}

PHP_MINIT (扩展模块加载时调用)

PHP_MSHUTDOWN (扩展模块加载时调用)

PHP_RINIT (每个请求开始时)

PHP_RSHUTDOWN (每个请求结束时)

一些基础介绍的博客链接

GET/POST等

http://blog.csdn.net/a600423444/article/details/7678164

内核相关学习资料

https://github.com/reeze/tipi

相关文章

  1. 如何通过xhprof分析性能

    使用方法 xhprof_enable(); /** ... 要检查的php代码 ... **/ $xhprof_data = xhprof_disable(); // 引入xhprof_lib i

  2. LUMEN API Controller 规范

    1. 第三方依赖库规范 在使用LUMEN实现API接口时,以下库必须需要包含在composer包依赖中,以实现代码编写的一些规范 dingo/api : 实现API接口库 vlucas/phpdo

  3. PHP文件锁

    共享锁(LOCK_SH) 什么时候加共享锁? 当在读取数据的时候同时进行着其他的写操作,这个时候需要对文件加共享锁,否则无论有没有对写操作加写锁都会写入成功,导致数据不一致 当文件获得共享锁时,其他

  4. Hello-Risen-程序

    首先需要说明的是,您下载到的文件包含两部分,其中src中是开发源码,用于对Risen框架本身的开发,risen 目录中是通过源码生成的包含debug和release版本的框架程序,用于您应用程序的开发

  5. PHP自定义类示例(Weixin消息解析类)

    PHP自定义类示例(Weixin消息解析类) /** * Created by Qingger. * User: jsspf * Date: 2017/3/24 * Time: 10:50

随机推荐

  1. 如何通过xhprof分析性能

    使用方法 xhprof_enable(); /** ... 要检查的php代码 ... **/ $xhprof_data = xhprof_disable(); // 引入xhprof_lib i

  2. LUMEN API Controller 规范

    1. 第三方依赖库规范 在使用LUMEN实现API接口时,以下库必须需要包含在composer包依赖中,以实现代码编写的一些规范 dingo/api : 实现API接口库 vlucas/phpdo

  3. PHP文件锁

    共享锁(LOCK_SH) 什么时候加共享锁? 当在读取数据的时候同时进行着其他的写操作,这个时候需要对文件加共享锁,否则无论有没有对写操作加写锁都会写入成功,导致数据不一致 当文件获得共享锁时,其他

  4. Hello-Risen-程序

    首先需要说明的是,您下载到的文件包含两部分,其中src中是开发源码,用于对Risen框架本身的开发,risen 目录中是通过源码生成的包含debug和release版本的框架程序,用于您应用程序的开发

  5. PHP自定义类示例(Weixin消息解析类)

    PHP自定义类示例(Weixin消息解析类) /** * Created by Qingger. * User: jsspf * Date: 2017/3/24 * Time: 10:50