文章详情

  • 游戏榜单
  • 软件榜单
关闭导航
热搜榜
热门下载
热门标签
php爱好者> php文档>编写扩展_II - 参数、数组和ZVALs[继续]

编写扩展_II - 参数、数组和ZVALs[继续]

时间:2007-12-21  来源:hshq_cn


               
.
[url=part%202-1.html#Heading1]介绍[/url]
.
[url=part%202-1.html#Heading2]接收数值[/url]
.
[url=part%202-1.html#Heading3]ZVAL[/url]
.
[url=part%202-1.html#Heading4]创建ZVALs[/url]
.
[url=part%202-1.html#Heading5]数组[/url]
.
[url=part%202-1.html#Heading6]符号表作为数组[/url]
.
[url=part%202-1.html#Heading7]引用计数[/url]
[url=#Heading8]拷贝 vs 引用[/url]
[url=#Heading9]核对(代码)完整性[/url]
[url=#Heading10]下一步是什么?[/url]
拷贝 vs 引用
有两种方法引用zval。第一种,如上文示范的,被称为写复制引用(copy-on-write
referencing)。第二种形式是完全引用(full referencing);当说起“引用”时,用户空间代码的编写者更熟悉这种,
以用户空间代码的形式出现类似于:$a = &$b;。
在zval中,这两种类型的区别在于它的is_ref成员的值,0表示写复制引用,非0表示完全引用。注意,一个zval不可能同时具有两种引用类型。所以,如果变量起初是is_ref(即完全引用-译注),然后以拷贝的方式赋给新的变量,那么必将执行一个完全拷贝。考虑下面的用户空间代码:
= 1;
$b = &$a;
$c = $a;
?>
在这段代码中,为$a创建并初始化了一个zval,将is_ref设为0,将refcount设为1。当$a被$b引用时,is_ref变为1,refcount递增至2。当拷贝至$c时,Zend引擎不能只是递增refcount至3,因为如此则$c变成了$a的完全引用。关闭is_ref也不行,因为如此会使$b看起来像是$a的一份拷贝而不是引用。所以此时分配了一个新的zval,并使用zval_copy_ctor()把原始(zval)的值拷贝给它。原始zval仍为is_ref==1、refcount==2,同时新zval则为is_ref=0、refcount=1。现在来看另一块内容相同的代码块,只是顺序稍有不同:
= 1;
$c = $a;
$b = &$a;
?>
最终结果不变,$b是$a的完全引用,并且$c是$a的一份拷贝。然而这次的内部效果稍有区别。如前,开始时为$a创建一个is_ref==0并且refcount=1的新zval。$c = $a;语句将同一个zval赋给$c变量,同时将refcount增至2,is_ref仍是0。当Zend引擎遇到$b = &$a;,它想要只是将is_ref设为1,但是当然不行,因为那将影响到$c。所以改为创建新的zval并用zval_copy_ctor()将原始(zval)的内容拷贝给它。然后递减原始zval的refcount以表明$a不再使用该zval。代替地,(Zend)设置新zval的is_ref为1、refcount为2,并且更新$a和$b变量指向它(新zval)。
核对(代码)完整性
如前,下面是我们的三个主要文件的完整代码:
config.m4
               
               
                PHP_ARG_ENABLE(hello, [whether to enable Hello World support],
[ --enable-hello   Enable Hello World support])
if test "$PHP_HELLO" = "yes"; then
AC_DEFINE(HAVE_HELLO, 1, [Whether you have Hello World])
      PHP_NEW_EXTENSION(hello, hello.c, $ext_shared)
fi
php_hello.h
#ifndef PHP_HELLO_H
#define PHP_HELLO_H 1
#ifdef ZTS
#include "TSRM.h"
#endif
ZEND_BEGIN_MODULE_GLOBALS(hello)
    long counter;
    zend_bool direction;
ZEND_END_MODULE_GLOBALS(hello)
#ifdef ZTS
#define HELLO_G(v) TSRMG(hello_globals_id, zend_hello_globals *, v)
#else
#define HELLO_G(v) (hello_globals.v)
#endif
#define PHP_HELLO_WORLD_VERSION "1.0"
#define PHP_HELLO_WORLD_EXTNAME "hello"
PHP_MINIT_FUNCTION(hello);
PHP_MSHUTDOWN_FUNCTION(hello);
PHP_RINIT_FUNCTION(hello);
PHP_FUNCTION(hello_world);
PHP_FUNCTION(hello_long);
PHP_FUNCTION(hello_double);
PHP_FUNCTION(hello_bool);
PHP_FUNCTION(hello_null);
PHP_FUNCTION(hello_greetme);
PHP_FUNCTION(hello_add);
PHP_FUNCTION(hello_dump);
PHP_FUNCTION(hello_array);
PHP_FUNCTION(hello_array_strings);
PHP_FUNCTION(hello_array_walk);
PHP_FUNCTION(hello_array_value);
PHP_FUNCTION(hello_get_global_var);
PHP_FUNCTION(hello_set_local_var);
extern zend_module_entry hello_module_entry;
#define phpext_hello_ptr &hello_module_entry
#endif
hello.c
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "php.h"
#include "php_ini.h"
#include "php_hello.h"
ZEND_DECLARE_MODULE_GLOBALS(hello)
static function_entry hello_functions[] = {
    PHP_FE(hello_world, NULL)
    PHP_FE(hello_long, NULL)
    PHP_FE(hello_double, NULL)
    PHP_FE(hello_bool, NULL)
    PHP_FE(hello_null, NULL)
    PHP_FE(hello_greetme, NULL)
    PHP_FE(hello_add, NULL)
    PHP_FE(hello_dump, NULL)
    PHP_FE(hello_array, NULL)
    PHP_FE(hello_array_strings, NULL)
    PHP_FE(hello_array_walk, NULL)
    PHP_FE(hello_array_value, NULL)
    PHP_FE(hello_get_global_var, NULL)
    PHP_FE(hello_set_local_var, NULL)
    {NULL, NULL, NULL}
};
zend_module_entry hello_module_entry = {
#if ZEND_MODULE_API_NO >= 20010901
    STANDARD_MODULE_HEADER,
#endif
    PHP_HELLO_WORLD_EXTNAME,
    hello_functions,
    PHP_MINIT(hello),
    PHP_MSHUTDOWN(hello),
    PHP_RINIT(hello),
    NULL,
    NULL,
#if ZEND_MODULE_API_NO >= 20010901
    PHP_HELLO_WORLD_VERSION,
#endif
    STANDARD_MODULE_PROPERTIES
};
#ifdef COMPILE_DL_HELLO
    ZEND_GET_MODULE(hello)
#endif
PHP_INI_BEGIN()
    PHP_INI_ENTRY("hello.greeting", "Hello World", PHP_INI_ALL, NULL)
    STD_PHP_INI_ENTRY("hello.direction", "1", PHP_INI_ALL, OnUpdateBool,\
        direction, zend_hello_globals, hello_globals)
PHP_INI_END()
static void php_hello_init_globals(zend_hello_globals *hello_globals)
{
    hello_globals->direction = 1;
}
PHP_RINIT_FUNCTION(hello)
{
    HELLO_G(counter) = 0;
    return SUCCESS;
}
PHP_MINIT_FUNCTION(hello)
{
    ZEND_INIT_MODULE_GLOBALS(hello, php_hello_init_globals, NULL);
    REGISTER_INI_ENTRIES();
    return SUCCESS;
}
PHP_MSHUTDOWN_FUNCTION(hello)
{
    UNREGISTER_INI_ENTRIES();
    return SUCCESS;
}
PHP_FUNCTION(hello_world)
{
    RETURN_STRING("Hello World", 1);
}
PHP_FUNCTION(hello_long)
{
    if (HELLO_G(direction)) {
        HELLO_G(counter)++;
    } else {
        HELLO_G(counter)--;
    }
    RETURN_LONG(HELLO_G(counter));
}
PHP_FUNCTION(hello_double)
{
    RETURN_DOUBLE(3.1415926535);
}
PHP_FUNCTION(hello_bool)
{
    RETURN_BOOL(1);
}
PHP_FUNCTION(hello_null)
{
    RETURN_NULL();
}
PHP_FUNCTION(hello_greetme)
{
    zval *zname;
    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &zname) == FAILURE) {
        RETURN_NULL();
    }
    convert_to_string(zname);
    php_printf("Hello ");
    PHPWRITE(Z_STRVAL_P(zname), Z_STRLEN_P(zname));
    php_printf("\n");
   
    RETURN_TRUE;
}
PHP_FUNCTION(hello_add)
{
    long a;
    double b;
    zend_bool return_long = 0;
    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ld|b",
        &a, &b, &return_long) == FAILURE) {
        RETURN_NULL();
    }
    if (return_long) {
        RETURN_LONG(a + b);
    } else {
        RETURN_DOUBLE(a + b);
    }
}
PHP_FUNCTION(hello_dump)
{
    zval *uservar;
    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &uservar) == FAILURE) {
    RETURN_NULL();
    }
    switch (Z_TYPE_P(uservar)) {
    case IS_NULL:
        php_printf("NULL\n");
        break;
    case IS_BOOL:
        php_printf("Boolean: %s\n", Z_LVAL_P(uservar) ? "TRUE" : "FALSE");
        break;
    case IS_LONG:
        php_printf("Long: %ld\n", Z_LVAL_P(uservar));
        break;
    case IS_DOUBLE:
        php_printf("Double: %f\n", Z_DVAL_P(uservar));
        break;
    case IS_STRING:
        php_printf("String: ");
        PHPWRITE(Z_STRVAL_P(uservar), Z_STRLEN_P(uservar));
        php_printf("\n");
        break;
    case IS_RESOURCE:
        php_printf("Resource\n");
        break;
    case IS_ARRAY:
        php_printf("Array\n");
        break;
    case IS_OBJECT:
        php_printf("Object\n");
        break;
    default:
        php_printf("Unknown\n");
    }
    RETURN_TRUE;
}
PHP_FUNCTION(hello_array)
{
    char *mystr;
    zval *mysubarray;
    array_init(return_value);
    add_index_long(return_value, 42, 123);
    add_next_index_string(return_value, "I should now be found at index 43", 1);
    add_next_index_stringl(return_value, "I'm at 44!", 10, 1);
    mystr = estrdup("Forty Five");
    add_next_index_string(return_value, mystr, 0);
    add_assoc_double(return_value, "pi", 3.1415926535);
    ALLOC_INIT_ZVAL(mysubarray);
    array_init(mysubarray);
    add_next_index_string(mysubarray, "hello", 1);
    php_printf("mysubarray->refcount = %d\n", mysubarray->refcount);
    mysubarray->refcount = 2;
    php_printf("mysubarray->refcount = %d\n", mysubarray->refcount);
    add_assoc_zval(return_value, "subarray", mysubarray);
    php_printf("mysubarray->refcount = %d\n", mysubarray->refcount);
}
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\n", 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)) {
        zval temp;
        char *key;
        int key_len;
        long index;
        if (zend_hash_get_current_key_ex(arr_hash, &key, &key_len,
            &index, 0, &pointer) == HASH_KEY_IS_STRING) {
            PHPWRITE(key, key_len);
        } else {
            php_printf("%ld", index);
        }
        php_printf(" => ");
        temp = **data;
        zval_copy_ctor(&temp);
        convert_to_string(&temp);
        PHPWRITE(Z_STRVAL(temp), Z_STRLEN(temp));
        php_printf("\n");
        zval_dtor(&temp);
    }
    RETURN_TRUE;
}
static int php_hello_array_walk(zval **element TSRMLS_DC)
{
    zval temp;
    temp = **element;
    zval_copy_ctor(&temp);
    convert_to_string(&temp);
    PHPWRITE(Z_STRVAL(temp), Z_STRLEN(temp));
    php_printf("\n");
    zval_dtor(&temp);
    return ZEND_HASH_APPLY_KEEP;
}
static int php_hello_array_walk_arg(zval **element, char *greeting TSRMLS_DC)
{
    php_printf("%s", greeting);
    php_hello_array_walk(element TSRMLS_CC);
    return ZEND_HASH_APPLY_KEEP;
}
static int php_hello_array_walk_args(zval **element, int num_args,
    var_list args, zend_hash_key *hash_key)
{
    char *prefix = va_arg(args, char*);
    char *suffix = va_arg(args, char*);
    TSRMLS_FETCH();
    php_printf("%s", prefix);
    php_hello_array_walk(element TSRMLS_CC);
    php_printf("%s\n", suffix);
    return ZEND_HASH_APPLY_KEEP;
}
PHP_FUNCTION(hello_array_walk)
{
    zval *zarray;
    int print_newline = 1;
    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a", &zarray) == FAILURE) {
        RETURN_NULL();
    }
    zend_hash_apply(Z_ARRVAL_P(zarray), (apply_func_t)php_hello_array_walk TSRMLS_CC);
    zend_hash_internal_pointer_reset(Z_ARRVAL_P(zarray));
    zend_hash_apply_with_argument(Z_ARRVAL_P(zarray),
        (apply_func_arg_t)php_hello_array_walk_arg, "Hello " TSRMLS_CC);
    zend_hash_apply_with_arguments(Z_ARRVAL_P(zarray),
        (apply_func_args_t)php_hello_array_walk_args, 2, "Hello ",
        "Welcome to my extension!");
    RETURN_TRUE;
}
PHP_FUNCTION(hello_array_value)
{
    zval *zarray, *zoffset, **zvalue;
    long index = 0;
    char *key = NULL;
    int key_len = 0;
    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "az",
        &zarray, &zoffset) == FAILURE) {
    RETURN_NULL();
    }
    switch (Z_TYPE_P(zoffset)) {
    case IS_NULL:
        index = 0;
        break;
    case IS_DOUBLE:
        index = (long)Z_DVAL_P(zoffset);
        break;
    case IS_BOOL:
    case IS_LONG:
    case IS_RESOURCE:
        index = Z_LVAL_P(zoffset);
        break;
    case IS_STRING:
        key = Z_STRVAL_P(zoffset);
        key_len = Z_STRLEN_P(zoffset);
        break;
    case IS_ARRAY:
        key = "Array";
        key_len = sizeof("Array") - 1;
        break;
    case IS_OBJECT:
        key = "Object";
        key_len = sizeof("Object") - 1;
        break;
    default:
        key = "Unknown";
        key_len = sizeof("Unknown") - 1;
    }
    if (key && zend_hash_find(Z_ARRVAL_P(zarray),
        key, key_len + 1, (void**)&zvalue) == FAILURE) {
        php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Undefined index: %s", key);
        RETURN_NULL();
    } else if (!key && zend_hash_index_find(Z_ARRVAL_P(zarray),
        index, (void**)&zvalue) == FAILURE) {
        php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Undefined index: %ld", index);
        RETURN_NULL();
    }
    *return_value = **zvalue;
    zval_copy_ctor(return_value);
}
PHP_FUNCTION(hello_get_global_var)
{
    char *varname;
    int varname_len;
    zval **varvalue;
    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s",
        &varname, &varname_len) == FAILURE) {
        RETURN_NULL();
    }
    if (zend_hash_find(&EG(symbol_table), varname, varname_len + 1,
        (void**)&varvalue) == FAILURE) {
        php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Undefined variable: %s", varname);
        RETURN_NULL();
    }
    *return_value = **varvalue;
    zval_copy_ctor(return_value);
}
PHP_FUNCTION(hello_set_local_var)
{
    zval *newvar;
    char *varname;
    int varname_len;
    zval *value;
    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz",
        &varname, &varname_len, &value) == FAILURE) {
        RETURN_NULL();
    }
    ALLOC_INIT_ZVAL(newvar);
    *newvar = *value;
    zval_copy_ctor(newvar);
    zend_hash_add(EG(active_symbol_table), varname, varname_len + 1,
        &newvar, sizeof(zval*), NULL);
    RETURN_TRUE;
}
下一步是什么?
在本教程-编写扩展系列的第二部分中,你学习了如何接收函数参数,创建并使用了数组,更重要的是了解了zval的内部运作方式。
[url=part%203.html]第3部分[/url]
将关注资源数据类型并开始处理更复杂的数据结构。
               
               

相关阅读 更多 +
排行榜 更多 +
翌日波奇狗的历险记手机版下载

翌日波奇狗的历险记手机版下载

休闲益智 下载
怪兽远征安卓版下载

怪兽远征安卓版下载

角色扮演 下载
谷歌卫星地图免费版下载

谷歌卫星地图免费版下载

生活实用 下载