您的位置:首页 > 编程语言 > PHP开发

PHP内核探索:数组源码分析

2011-06-09 00:00 2111 查看
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, "value", 0);
zend_hash_add(h, "key", 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, char *key, long lval);
add_assoc_double(zval *aval, char *key, double dval);
add_assoc_string(zval *aval, char *key, char *strval, int dup);
add_assoc_stringl(zval *aval, char *key,char *strval, uint strlen, int dup);
add_assoc_zval(zval *aval, char *key, 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, ulong idx, int b    );
ZEND_API int add_index_resource (zval *arg, ulong idx, int r    );
ZEND_API int add_index_double   (zval *arg, ulong idx, double d);
ZEND_API int add_index_string   (zval *arg, ulong idx, const char *str, int duplicate);
ZEND_API int add_index_stringl  (zval *arg, ulong idx, const char *str, 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, const char *str, int duplicate);
ZEND_API int add_next_index_stringl     (zval *arg, const char *str, uint length, 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, 4, "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", "foo", 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。

延伸阅读

此文章所在专题列表如下:

PHP内核探索:从SAPI接口开始

PHP内核探索:一次请求的开始与结束

PHP内核探索:一次请求生命周期

PHP内核探索:单进程SAPI生命周期

PHP内核探索:多进程/线程的SAPI生命周期

PHP内核探索:Zend引擎

PHP内核探索:再次探讨SAPI

PHP内核探索:Apache模块介绍

PHP内核探索:通过mod_php5支持PHP

PHP内核探索:Apache运行与钩子函数

PHP内核探索:嵌入式PHP

PHP内核探索:PHP的FastCGI

PHP内核探索:如何执行PHP脚本

PHP内核探索:PHP脚本的执行细节

PHP内核探索:操作码OpCode

PHP内核探索:PHP里的opcode

PHP内核探索:解释器的执行过程

PHP内核探索:变量概述

PHP内核探索:变量存储与类型

PHP内核探索:PHP中的哈希表

PHP内核探索:理解Zend里的哈希表

PHP内核探索:PHP哈希算法设计

PHP内核探索:翻译一篇HashTables文章

PHP内核探索:哈希碰撞攻击是什么?

PHP内核探索:常量的实现

PHP内核探索:变量的存储

PHP内核探索:变量的类型

PHP内核探索:变量的值操作

PHP内核探索:变量的创建

PHP内核探索:预定义变量

PHP内核探索:变量的检索

PHP内核探索:变量的类型转换

PHP内核探索:弱类型变量的实现

PHP内核探索:静态变量的实现

PHP内核探索:变量类型提示

PHP内核探索:变量的生命周期

PHP内核探索:变量赋值与销毁

PHP内核探索:变量作用域

PHP内核探索:诡异的变量名

PHP内核探索:变量的value和type存储

PHP内核探索:全局变量Global

PHP内核探索:变量类型的转换

PHP内核探索:内存管理开篇

PHP内核探索:Zend内存管理器

PHP内核探索:PHP的内存管理

PHP内核探索:内存的申请与销毁

PHP内核探索:引用计数与写时复制

PHP内核探索:PHP5.3的垃圾回收机制

PHP内核探索:内存管理中的cache

PHP内核探索:写时复制COW机制

PHP内核探索:数组与链表

PHP内核探索:使用哈希表API

PHP内核探索:数组操作

PHP内核探索:数组源码分析

PHP内核探索:函数的分类

PHP内核探索:函数的内部结构

PHP内核探索:函数结构转换

PHP内核探索:定义函数的过程

PHP内核探索:函数的参数

PHP内核探索:zend_parse_parameters函数

PHP内核探索:函数返回值

PHP内核探索:形参return value

PHP内核探索:函数调用与执行

PHP内核探索:引用与函数执行

PHP内核探索:匿名函数及闭包

PHP内核探索:面向对象开篇

PHP内核探索:类的结构和实现

PHP内核探索:类的成员变量

PHP内核探索:类的成员方法

PHP内核探索:类的原型zend_class_entry

PHP内核探索:类的定义

PHP内核探索:访问控制

PHP内核探索:继承,多态与抽象类

PHP内核探索:魔术函数与延迟绑定

PHP内核探索:保留类与特殊类

PHP内核探索:对象

PHP内核探索:创建对象实例

PHP内核探索:对象属性读写

PHP内核探索:命名空间

PHP内核探索:定义接口

PHP内核探索:继承与实现接口

PHP内核探索:资源resource类型

PHP内核探索:Zend虚拟机

PHP内核探索:虚拟机的词法解析

PHP内核探索:虚拟机的语法分析

PHP内核探索:中间代码opcode的执行

PHP内核探索:代码的加密与解密

PHP内核探索:zend_execute的具体执行过程

PHP内核探索:变量的引用与计数规则

PHP内核探索:新垃圾回收机制说明
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: