-
Notifications
You must be signed in to change notification settings - Fork 0
PHP Extension Develop and Test
yourlovemyall edited this page Oct 28, 2017
·
7 revisions
$con = mysql_connect("localhost","peter","abc123");
$redis = new Redis();
$redis->connect('127.0.0.1', 6379);
$ /$path/phpize
$ ./configure + php-cofnig
$ make && make install
$ 添加生成的 ext.so 到 php.ini
- config.m4为配置定义文件,用来读取编译命令。
- myext.so为编译后生成的二进制文件。
- 代码在myext.c中,编译完成并且加入到php.ini后。
- 运行 $ php test.php
- config.m4
- php_{extname}.h
- {extname}.c
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)
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
};
extern zend_module_entry myext_module_entry;
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),这四个函数会在相应时机被调用,分别是“扩展模块加载时”、“扩展模块卸载时”、“每个请求开始时”和“每个请求结束时”。这四个函数可以看成是一种拦截机制,主要用于相应时机的资源分配、释放等相关操作。 (后面再说)
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
};
#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,代表用户端在调用此函数时有没有使用到它的返回值。
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如此重要,内核肯定早已经为它准备了大量的宏,来简化我们的操作,提高程序的质量。 在前几章我们接触的宏大多都是以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();
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();
}
}
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;
}
INIT_CLASS_ENTRY(redis_class_entry, "Myredis", myredis_functions); //注册类
redis_ce = zend_register_internal_class(&redis_class_entry TSRMLS_CC);
#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)
};
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_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},
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
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;
EG()、这个宏可以用来访问符号表,函数,资源信息和常量
CG() 用来访问核心全局变量
PG() PHP全局变量。我们知道php.ini会映射一个或者多个PHP全局结构。举几个使用这个宏的例子:PG(register_globals), PG(safe_mode), PG(memory_limit)
FG() 文件全局变量。大多数文件I/O或相关的全局变量的数据流都塞进标准扩展出口结构。
/* 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)
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);
}
{
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);
}
nm /usr/local/php/bin/php |grep fopen
gdb php
break php_if_fopen
run /home/xuxiaoyu/test.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);
}
http://blog.csdn.net/a600423444/article/details/7678164
https://github.com/reeze/tipi