码迷,mamicode.com
首页 > Web开发 > 详细

PHP变量存储结构

时间:2015-01-13 12:17:17      阅读:150      评论:0      收藏:0      [点我收藏+]

标签:

首先声明,我并没有去读PHP的源码,只是对于PHP的有时候诡异的表现感兴趣,找了一下开发人员laruence的博客结合PHP提供的函数debug_zval_dump刺探得到了本博客所阐述的工作机理。如果你想对PHP变量存储结构有一个了解或想对PHP变量加深理解的话,本文是适合你的,比较深入的去看源代码吧。

为了保证博客的连贯性,首先引用laruence关于PHP变量内部存储结构的部分内容(稍作修改)

 


 

在PHP中,所有的变量都是用一个结构-zval来保存的, 在Zend/zend.h中我们可以看到zval的定义:

  1.   typedef struct _zval_struct {
  2.     zvalue_value value;
  3.     zend_uint refcount;
  4.     zend_uchar type;
  5.     zend_uchar is_ref;
  6.   } zval;
  7.  

其中zvalue_value是真正保存数据的关键部分,定义为一个联合体(union)

  1. typedef union _zvalue_value {
  2.     long lval;
  3.     double dval;
  4.     struct {
  5.         char *val;
  6.         int len;
  7.     } str;
  8.     HashTable *ht;
  9.     zend_object_value obj;
  10. } zvalue_value;

PHP中常见的变量类型有:

  1. 1. 整型/浮点/长整型/bool值 等等
  2. 2. 字符串
  3. 3. 数组/关联数组
  4. 4. 对象
  5. 5. 资源
  6.  

PHP根据zval中的type字段来储存一个变量的真正类型,然后根据type来选择如何获取zvalue_value的值,比如对于整型和bool值:

  1.    zval.type = IS_LONG;//整形
  2.    zval.type = IS_BOOL;//布尔值

就去取zval.value.lval,对于bool值来说lval∈(0|1);如果是双精度,或者float则会去取zval.value的dval。而如果是字符串,那么:

  1.    zval.type = IS_STRING

这个时候,就会取:zval.value.str而这个也是个结构,存有C分格的字符串和字符串的长度。

而对于数组和对象,则type分别对应IS_ARRAY, IS_OBJECT, 相对应的则分别取zval.value.ht和obj

比较特别的是资源,在PHP中,资源是个很特别的变量,任何不属于PHP内建的变量类型的变量,都会被看作成资源来进行保存,比如,数据库句柄,打开的文件句柄等等。 对于资源:

  1.    type = IS_RESOURCE

这个时候,会去取zval.value.lval, 此时的lval是个整型的指示器, 然后PHP会再根据这个指示器在PHP内建的一个资源列表中查询相对应的资源,此时的lval就好像是对应于资源链表的偏移值。

  1.  ZEND_FETCH_RESOURCE(con, type, zval *, default, resource_name, resource_type);

借用这样的机制,PHP就实现了弱类型,因为对于ZE的来说,它所面对的永远都是同一种类型,那就是zval。


上面部分博文只是阐明了PHP变量的内部表示,要想知道内部表示是如何和用户脚本中的变量联系起来的,需要看laruence的另一篇博文深入理解PHP原理之变量作用域(Scope in PHP),同样引用部分内容(稍作修改)如下:

 


如果在脚本中写下:

  1. <?php
  2.   $var = "laruence";
  3.   echo $var;
  4. ?>

ZE是如何把我的变量var和内部结构zval联系起来的呢?

PHP内部都是使用zval来表示变量的,但是对于上面的脚本,我们的变量是有名字的, var。而zval中并没有相应的字段来体现变量名。PHP内部一定有一个机制,来实现变量名到zval的映射。

在PHP中,所有的变量都会存储在一个数组中(确切的说是hash table)。

当你创建一个变量的时候,PHP会为这个变量分配一个zval,填入相应的变量值,然后将这个变量的名字,和指向这个zval的指针填入一个数组中。然后,当你获取这个变量的时候,PHP会通过查找这个数组,获得对应的zval。

查看_zend_executor_globals结构(这个结构在PHP的执行器保存一些执行相关的上下文信息)

  1. struct _zend_executor_globals {
  2.  
  3.      ....
  4.     HashTable *active_symbol_table;/*活动符号表*/
  5.     HashTable symbol_table; /*全局符号表*/
  6.  
  7.     HashTable included_files;
  8.  
  9.     jmp_buf *bailout;
  10.     int error_reporting;
  11.      .....
  12. }
  13.  

总结以上两篇博客,对于如下程序

 

  1. <?php  
  2. class class1  
  3. {  
  4.     public $member;  
  5.       
  6.     function __construct()  
  7.     {  
  8.         $this->member = 1;  
  9.     }  
  10. }  
  11.   
  12. $a = 1;  
  13. $b = 0.56;  
  14. $c = "string";  
  15. $d = array(1=>1);  
  16. $e = new class1;  
  17. $f = tmpfile();  
  18.   
  19. debug_zval_dump($a);  
  20. debug_zval_dump($b);  
  21. debug_zval_dump($c);  
  22. debug_zval_dump($d);  
  23. debug_zval_dump($e);  
  24. debug_zval_dump($f);  
  25. ?>  

该程序使用debug_zval_dump刺探LONG、DOUBLE、STRING、ARRAY、OBJECT、RESOURCE类型变量,结果如下

 

 

  1. long(1) refcount(2)  
  2. double(0.56) refcount(2)  
  3. string(6) "string" refcount(2)  
  4. array(1) refcount(2){  
  5.   [1]=>  
  6.   long(1) refcount(1)  
  7. }  
  8. object(class1)#1 (1) refcount(2){  
  9.   ["member"]=>  
  10.   long(1) refcount(1)  
  11. }  
  12. resource(4) of type (stream) refcount(2)  

分析绘制整个存储结构如下
技术分享

 

对照此图就可以知道PHP各种类型的变量在内存中存储结构和用户变量如何跟内存结构挂钩,了解了这些是下一篇博文关于PHP引用详解的基础。期待下一篇PHP的赋值行为详解吧。

PHP变量存储结构

标签:

原文地址:http://www.cnblogs.com/killallspree/p/4220558.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!