设为首页 收藏本站
查看: 606|回复: 0

[经验分享] 原创:PHP内核研究:数组的创建

[复制链接]

尚未签到

发表于 2017-3-30 09:20:51 | 显示全部楼层 |阅读模式
声明:本文为斯人原创,全部为作者一一分析得之,有不对的地方望赐教。

博客地址:PHP技术博客在CSDN也会同步更新的哦.

欢迎转载,转载请注明出处


PHP之所以发现这么迅速,有很大原因是因为数组数据非常好处理,而且它可以存储其他类型的数据

数组的值存储在zvalue_value.ht字段中,ht是一个HashTable的数据

有关于HashTable的知识请移步 >>HASH表和变量

我们来详细说一下数组

PHP里面所有的数据都离不开zval和HashTable,

一个PHP很简单的数组初始化,

在C语言里面实现的却没有那么简单.

经过简单分析,找到数组的初始化的opcode

在Zend/zend_vm_execute.h文件中

[c]
static int ZEND_FASTCALL  ZEND_INIT_ARRAY_SPEC_CV_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
{
        zend_op *opline = EX(opline);

        array_init(&EX_T(opline->result.u.var).tmp_var); //分配数组内存空间,初始化
        if (IS_CV == IS_UNUSED) {
                ZEND_VM_NEXT_OPCODE();
#if 0 || IS_CV != IS_UNUSED
        } else {
                return ZEND_ADD_ARRAY_ELEMENT_SPEC_CV_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
#endif        }
}
[/c]




初始化数组的函数是 array_init

看看它的定义

[c]
ZEND_API int _array_init(zval *arg, uint size ZEND_FILE_LINE_DC) /* {{{ */
{
        ALLOC_HASHTABLE_REL(Z_ARRVAL_P(arg)); //分配内存

        _zend_hash_init(Z_ARRVAL_P(arg), size, NULL, ZVAL_PTR_DTOR, 0 ZEND_FILE_LINE_RELAY_CC);
        Z_TYPE_P(arg) = IS_ARRAY; //类型为数组
        return SUCCESS;
}
[/c]

看到没有,Hash表初始化函数_zend_hash_init

如果对Hash表不清楚 ,猛点这里>>PHP内核研究第二步:HASH表和变量

下面我们实验一下,

用扩展创建一个空数组,然后用PHP var_dump;

至于如何扩展PHP这里不谈

关键代码

[c]
PHP_FUNCTION(confirm_siren_compiled)
{
        zval *value;
        MAKE_STD_ZVAL(value);
        array_init(value);
        ZEND_SET_SYMBOL(EG(active_symbol_table),"siren",value);

[/c]

PHP执行代码

[c]
<!--?php dl("siren.so"); confirm_siren_compiled(1); var_dump($siren); ?-->
[/c]

用命令执行 输出

s# /usr/local/php53/bin/php test.php

array(0) {

}

我们成功创建了一个空数组,如果看过 变量那一章的内容,应该会明白confirm_siren_compiled都做了什么

不懂的话 猛击>>PHP内核研究第二步:HASH表和变量

但是创建一个空数组 ,是没有意义的,如何添加键,值?

添加一个元素的关键代码

[c]
PHP_FUNCTION(confirm_siren_compiled)
{
        zval *value;
        zval *element;
        char *s="this is a value";
        char *key="a";
        MAKE_STD_ZVAL(element);
        MAKE_STD_ZVAL(value);
        array_init(value);
        ZVAL_STRING(element,s,strlen(s));
        zend_hash_update(value->value.ht,key,strlen(key)+1,(void*)&element,sizeof(zval*),NULL);
        ZEND_SET_SYMBOL(EG(active_symbol_table),"siren",value);
}
[/c]

执行PHP 结果如下

s# /usr/local/php53/bin/php test.php

array(1) {

["a"]=>

string(15) "this is a value"

}

zend_hash_update只是给数组添加元素的一种方法 ..

还有很多API可以用,


[c]

函数                                  说明
add_assoc_long(zval *array, char *key, long n);  添加一个长整型元素。
add_assoc_unset(zval *array, char *key);       添加一个 unset 元素。
add_assoc_bool(zval *array, char *key, int b);    添加一个布尔值。
add_assoc_resource(zval *array, char *key, int r); 添加一个资源。
add_assoc_double(zval *array, char *key, double d); 添加一个浮点值。
add_assoc_string(zval *array, char *key, char *str, int duplicate); 添加一个字符串。duplicate 用于表明这个字符串是否要被复制到 Zend 的内部内存。
add_assoc_stringl(zval *array, char *key, char *str, uint length, int duplicate); 添加一个指定长度的字符串。其余跟add_assoc_string () 相同。
add_assoc_zval(zval *array, char *key, zval *value); 添加一个 zval 结构。 这在添加另外一个数组、对象或流等数据时会很有用
add_index_long(zval *array, uint idx, long n); 添加一个长整型元素。
add_index_unset(zval *array, uint idx); 添加一个 unset 元素。
add_index_bool(zval *array, uint idx, int b); 添加一个布尔值。
add_index_resource(zval *array, uint idx, int r); 添加一个资源。
add_index_double(zval *array, uint idx, double d); 添加一个浮点值。
add_index_string(zval *array, uint idx, char *str, int duplicate); 添加一个字符串。duplicate 用于表明这个字符串是否要被复制到 Zend 的内部内存。
add_index_stringl(zval *array, uint idx, char *str, uint length, int duplicate); 添加一个指定长度的字符串。其余跟add_index_string () 相同。
add_index_zval(zval *array, uint idx, zval *value); 添加一个 zval 结构。 这在添加另外一个数组、对象或流等数据时会很有用。
add_next_index_long(zval *array, long n); 添加一个长整型元素。
add_next_index_unset(zval *array); 添加一个 unset 元素。
add_next_index_bool(zval *array, int b); 添加一个布尔值。
add_next_index_resource(zval *array, int r); 添加一个资源。
add_next_index_double(zval *array, double d); 添加一个浮点值。
add_next_index_string(zval *array, char *str, int duplicate); 添加一个字符串。duplicate 用于表明这个字符串是否要被复制到 Zend 的内部内存。
add_next_index_stringl(zval *array, char *str, uint length, int duplicate); 添加一个指定长度的字符串。其余跟add_next_index_string () 相同。
add_next_index_zval(zval *array, zval *value); 添加一个 zval 结构。 这在添加另外一个数组、对象或流等数据时会很有用。
[/c]



具体使用方法很简单,看参数名称就知道方法了,自己试验吧...

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-357401-1-1.html 上篇帖子: 如何编译PHP源代码(ZEND) 下篇帖子: PHP中的__FILE,__CLASS等魔术变量
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表