54-数组源码分析
PHP中经常使用数组,使用数组最大的好处便是速度!读写都可以在O(1)内完成,因为它每个元素的大小都是一致的,只要知道下标,便可以瞬间计算出其对应的元素在内存中的位置,从而直接取出或者写入。那么内核中是如何实现的呢? PHP大部分功能,都是通过HashTable来实现,其中就包括数组。HashTable即具有双向链表的优点,同时具有能与数据匹敌的操作性能。PHP中的定义的变量保存在一个符号表里,而这个符号表其实就是一个HashTable,它的每一个元素都是一个zval*类型的变量。不仅如此,保存用户定义的函数、类、资源等的容器都是以HashTable的形式在内核中实现的。 下面分别来看在PHP、内核中如何定义数组。 PHP中定义数组: <?php $array = array(); $array["key"] = "values"; ?> 在内核中使用宏来实现: zval* array; array_init(array); add_assoc_string(array,"key","value",1); 将上述代码中的宏展开: zval* array; ALLOC_INIT_ZVAL(array); Z_TYPE_P(array) = IS_ARRAY; HashTable *h; ALLOC_HASHTABLE(h); Z_ARRVAL_P(array)=h; zend_hash_init(h,50,NULL,ZVAL_PTR_DTOR,0); zval* barZval; MAKE_STD_ZVAL(barZval); ZVAL_STRING(barZval,0); zend_hash_add(h,4,&barZval,sizeof(zval*),NULL); 内核为我们提供了方便的宏来管理数组。 //add_assoc_*系列函数: add_assoc_null(zval *aval,char *key); add_assoc_bool(zval *aval,char *key,zend_bool bval); add_assoc_long(zval *aval,long lval); add_assoc_double(zval *aval,double dval); add_assoc_string(zval *aval,char *strval,int dup); add_assoc_stringl(zval *aval,uint strlen,int dup); add_assoc_zval(zval *aval,zval *value); //备注:其实这些函数都是宏,都是对add_assoc_*_ex函数的封装。 //add_index_*系列函数: ZEND_API int add_index_long (zval *arg,ulong idx,long n); ZEND_API int add_index_null (zval *arg,ulong idx ); ZEND_API int add_index_bool (zval *arg,int b ); ZEND_API int add_index_resource (zval *arg,int r ); ZEND_API int add_index_double (zval *arg,double d); ZEND_API int add_index_string (zval *arg,const char *str,int duplicate); ZEND_API int add_index_stringl (zval *arg,uint length,int duplicate); ZEND_API int add_index_zval (zval *arg,ulong index,zval *value); //add_next_index_*函数: ZEND_API int add_next_index_long (zval *arg,long n ); ZEND_API int add_next_index_null (zval *arg ); ZEND_API int add_next_index_bool (zval *arg,int b ); ZEND_API int add_next_index_resource (zval *arg,int r ); ZEND_API int add_next_index_double (zval *arg,double d); ZEND_API int add_next_index_string (zval *arg,int duplicate); ZEND_API int add_next_index_stringl (zval *arg,int duplicate); ZEND_API int add_next_index_zval (zval *arg,zval *value); add_next_index_*() PHP中 内核中 $arr[] = NULL; add_next_index_null(arr); $arr[] = 42; add_next_index_long(arr,42); $arr[] = true; add_next_index_bool(arr,1); $arr[] = 3.14; add_next_index_double(arr,3.14); $arr[] = 'foo'; add_next_index_string(arr,"foo"); $arr[] = $var; add_next_index_zval(arr,zval); add_index_*() PHP中 内核中 $arr[0] = NULL; add_index_null(arr,0); $arr[1] = 42; add_index_long(arr,1,42); $arr[2] = true; add_index_bool(arr,2,1); $arr[3] = 3.14; add_index_double(arr,3,3.14); $arr[4] = 'foo'; add_index_string(arr,"foo",1); $arr[5] = $var; add_index_zval(arr,5,zval); add_assoc_*() $arr["abc"] = NULL; add_assoc_null(arr,"abc"); $arr["def"] = 42; add_assoc_long(arr,"def",42); $arr["ghi"] = true; add_assoc_bool(arr,"ghi",1); $arr["jkl"] = 3.14 add_assoc_double(arr,"jkl",3.14); $arr["mno"]="foo" add_assoc_string(arr,"mno",1"); $arr["pqr"] = $var; add_assoc_zval(arr,"pqr",zval); 下面在PHP中定义一个函数,并在其中使用数组。然后来看在内核中如何实现。 <?php function array_test(){ $mystr = "Forty Five"; $return_value = array(); $return_value[42] = 123; $return_value[] = "test"; $return_value[] = $mystr; $return_value["double"] = 3.14; $mysubarray; $mysubarray = array(); $mysubarray[] = "hello"; $return_value["subarray"] = $mysubarray; return $return_value; } ?> 内核中实现: PHP_FUNCTION(array_test){ char* mystr; zval* mysubarray; array_init(return_value); add_index_long(return_value,42,123); add_next_index_string(return_value,"test",1); add_next_index_stringl(return_value,"test_stringl",10,1); mystr = estrdup("Forty Five"); add_next_index_string(return_value,mystr,0); add_assoc_double(return_value,"double",3.14); ALLOC_INIT_ZVAL(mysubarray); array_init(mysubarray); add_next_index_string(mysubarray,"hello",1); add_assoc_zval(return_value,"subarray",mysubarray); } 你可能会疑问上面代码中的变量return_value在哪里定义的。下面将PHP_FUNCTION展开,你就明白了。 zif_array_test(int ht,zval *return_value,zval **return_value_ptr,zval *this_ptr,int return_value_used TSRMLS_DC); 没错,实际上每个函数都有一个默认的返回值return_value。在使用RETVAL_()、RETURN_()作为函数返回值时,仅仅是修改return_value。 原文:大专栏 ?54-数组源码分析 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |