首先声明,我并没有去读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;

其中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. 资源

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. HashTable *active_symbol_table;/*活动符号表*/
  4. HashTable symbol_table; /*全局符号表*/
  5. HashTable included_files;
  6. jmp_buf *bailout;
  7. int error_reporting;
  8. .....
  9. }

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

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

该程序使用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变量存储结构的更多相关文章

  1. 深入PHP变量存储结构 标签: PHP存储

    1.深入PHP变量存储结构 标签: PHP存储  分类: 编程语言(10)  首先声明,我并没有去读PHP的源码,只是对于PHP的有时候诡异的表现感兴趣,找了一下开发人员laruence的博客结合PH ...

  2. 深入理解PHP内核(五)变量及数据类型-变量的结构和类型

    原文链接:http://www.orlion.ga/238/ 编程语言的类型可以分为强类型和弱类型两种,PHP是弱类型语言,但是C语言是强类型语言.在官网PHP实现内部,所有变量使用同一种数据结构(z ...

  3. 队列的存储结构和常见操作(c 语言实现)

    一.队列(queue) 队列和栈一样,在实际程序的算法设计和计算机一些其他分支里,都有很多重要的应用,比如计算机操作系统对进程 or 作业的优先级调度算法,对离散事件的模拟算法,还有计算机主机和外部设 ...

  4. Oracle使用%rowtype变量存储一行数据

    在Oracle中,%rowtype是用来存储一行数据的 语法: rowType_name table_name%rowtype rowType_name :变量名 table_name:指定的表名 具 ...

  5. (续)一个demo弄清楚位图在内存中的存储结构

    本来续---数字图像处理之位图在计算机中的存储结构一文,通过参考别人的代码,进行修改和测试终于成功运行. 该实例未使用任何API和相关类,相信如果对此实例能够完全理解那么将有进一步进行数字图像处理的能 ...

  6. PostgreSQL的存储系统二:REDOLOG文件存储结构二

    REDOLOG文件里的用户数据和数据文件里的用户数据存储结构相同 几个月前同事给台湾一家公司培训<pg9 ad admin>时,有个学员提及WAL里记录的内容为Query时的SQL语句(比 ...

  7. PHP内核变量存储

    PHP作为一门弱类型语言,其变量类型可任意改变.而C作为PHP的底层实现,是通过结构及联合来实现PHP变量的弱类型特性的.在PHP源码中,Zend/zend.h文件有关于PHP变量的结构定义. 01 ...

  8. .Net程序员学用Oracle系列(26):PLSQL 之类型、变量和结构

    1.类型 1.1.属性类型 1.2.记录类型 2.变量 2.1.变量类型 2.2.变量定义 2.3.变量赋值 3.结构 3.1.顺序结构 3.2.选择结构 3.3.循环结构 4.总结 1.类型 在&l ...

  9. c语言的作用域、变量与结构体

    一.变量的作用域 根据变量的作用域,可以分为: 1.局部变量: 1> 定义:在函数(代码块)内部定义的变量(包括函数的形参) 2> 作用域:局部变量只有在定义它的函数内部使用,其它函数不能 ...

随机推荐

  1. 利用数目找中位数(牛客第七场E)

    https://ac.nowcoder.com/acm/contest/887/E 树状数组做法(代码有注释) #include<bits/stdc++.h> using namespac ...

  2. 玩转SpringBoot用好条件相关注解,开启自...

    官方提供的常用条件注解 因为Spring的核心是基于bean的,所以这些条件注解主要是影响bean的注册. 因为注册的bean不同了,最后对外呈现的行为就不同了.不就是自动配置了. 一.最常用的应该是 ...

  3. import org.apache.commons.codec.binary.Base64;

    import org.apache.commons.codec.binary.Base64;

  4. 《内蒙古自治区第十二届大学生程序设计竞赛试题_G: 最大收益》

    问题 G: 最大收益 内存限制:128 MB时间限制:1 S标准输入输出 题目类型:传统评测方式:文本比较上传者:外部导入 提交:87通过:23 返回比赛提交提交记录 题目描述 Elly的叔叔经营一家 ...

  5. Struts2开发基本步骤

    1 加载jar文件   commons-fileupload.jar   commons-io.jar   commons-lang.jar   freemaker.jar   ognl.jar   ...

  6. 【GBK、UTF-8、ISO8859-1】三种编码方式总结及实例

    感谢:https://blog.csdn.net/youngstar70/article/details/64117297 一.总结 在Java中,String的getBytes()方法是得到一个操作 ...

  7. 流量全球第4的Reddit到底是一个怎样的网站?

    对于喜欢NBA的我来说,Reddit是经常接触的一个网站.或者说,很多关于NBA的最新消息都是从Reddit上传出来的.值得一提的是,NBA版块在Reddit所有版块中用户活跃程度排名第三,也是体育版 ...

  8. Waymo

    技术优势 Waymo在自己的激光雷达系统上投入了大量资金,它认为这项技术对自动驾驶汽车的长期成功至关重要.实际上,该公司声称它已经将专有激光雷达传感器的成本降低了90%,这种传感器以前的制造成本为7. ...

  9. annoy超平面多维近似向量查找工具

    需求:有800万的中文词向量,要查询其中任意一个词向量对应的k个与其最邻近的向量.通常情况下如果向量集比较小的话,几十万个向量(几个G这种),我们都可以用gensim的word2vec来查找,但是88 ...

  10. ThinkPHP使用soapclient调用webservice接口

    1,开启 php.ini 这2个服务 12 extension=php_openssl.dllextension=php_soap.dll 以公共天气预报webservice为例,采用thinkPHP ...