PHP变量存储结构
首先声明,我并没有去读PHP的源码,只是对于PHP的有时候诡异的表现感兴趣,找了一下开发人员laruence的博客结合PHP提供的函数debug_zval_dump刺探得到了本博客所阐述的工作机理。如果你想对PHP变量存储结构有一个了解或想对PHP变量加深理解的话,本文是适合你的,比较深入的去看源代码吧。
为了保证博客的连贯性,首先引用laruence关于PHP变量内部存储结构的部分内容(稍作修改)
在PHP中,所有的变量都是用一个结构-zval来保存的, 在Zend/zend.h中我们可以看到zval的定义:
- typedef struct _zval_struct {
- zvalue_value value;
- zend_uint refcount;
- zend_uchar type;
- zend_uchar is_ref;
- } zval;
其中zvalue_value是真正保存数据的关键部分,定义为一个联合体(union)
- typedef union _zvalue_value {
- long lval;
- double dval;
- struct {
- char *val;
- int len;
- } str;
- HashTable *ht;
- zend_object_value obj;
- } zvalue_value;
PHP中常见的变量类型有:
- 1. 整型/浮点/长整型/bool值 等等
- 2. 字符串
- 3. 数组/关联数组
- 4. 对象
- 5. 资源
PHP根据zval中的type字段来储存一个变量的真正类型,然后根据type来选择如何获取zvalue_value的值,比如对于整型和bool值:
- zval.type = IS_LONG;//整形
- zval.type = IS_BOOL;//布尔值
就去取zval.value.lval,对于bool值来说lval∈(0|1);如果是双精度,或者float则会去取zval.value的dval。而如果是字符串,那么:
- zval.type = IS_STRING
这个时候,就会取:zval.value.str而这个也是个结构,存有C分格的字符串和字符串的长度。
而对于数组和对象,则type分别对应IS_ARRAY, IS_OBJECT, 相对应的则分别取zval.value.ht和obj
比较特别的是资源,在PHP中,资源是个很特别的变量,任何不属于PHP内建的变量类型的变量,都会被看作成资源来进行保存,比如,数据库句柄,打开的文件句柄等等。 对于资源:
- type = IS_RESOURCE
这个时候,会去取zval.value.lval, 此时的lval是个整型的指示器, 然后PHP会再根据这个指示器在PHP内建的一个资源列表中查询相对应的资源,此时的lval就好像是对应于资源链表的偏移值。
- ZEND_FETCH_RESOURCE(con, type, zval *, default, resource_name, resource_type);
借用这样的机制,PHP就实现了弱类型,因为对于ZE的来说,它所面对的永远都是同一种类型,那就是zval。
上面部分博文只是阐明了PHP变量的内部表示,要想知道内部表示是如何和用户脚本中的变量联系起来的,需要看laruence的另一篇博文深入理解PHP原理之变量作用域(Scope in PHP),同样引用部分内容(稍作修改)如下:
如果在脚本中写下:
- <?php
- $var = "laruence";
- echo $var;
- ?>
ZE是如何把我的变量var和内部结构zval联系起来的呢?
PHP内部都是使用zval来表示变量的,但是对于上面的脚本,我们的变量是有名字的, var。而zval中并没有相应的字段来体现变量名。PHP内部一定有一个机制,来实现变量名到zval的映射。
在PHP中,所有的变量都会存储在一个数组中(确切的说是hash table)。
当你创建一个变量的时候,PHP会为这个变量分配一个zval,填入相应的变量值,然后将这个变量的名字,和指向这个zval的指针填入一个数组中。然后,当你获取这个变量的时候,PHP会通过查找这个数组,获得对应的zval。
查看_zend_executor_globals结构(这个结构在PHP的执行器保存一些执行相关的上下文信息)
- struct _zend_executor_globals {
- ....
- HashTable *active_symbol_table;/*活动符号表*/
- HashTable symbol_table; /*全局符号表*/
- HashTable included_files;
- jmp_buf *bailout;
- int error_reporting;
- .....
- }
总结以上两篇博客,对于如下程序
- <?php
- class class1
- {
- public $member;
- function __construct()
- {
- $this->member = 1;
- }
- }
- $a = 1;
- $b = 0.56;
- $c = "string";
- $d = array(1=>1);
- $e = new class1;
- $f = tmpfile();
- debug_zval_dump($a);
- debug_zval_dump($b);
- debug_zval_dump($c);
- debug_zval_dump($d);
- debug_zval_dump($e);
- debug_zval_dump($f);
- ?>
该程序使用debug_zval_dump刺探LONG、DOUBLE、STRING、ARRAY、OBJECT、RESOURCE类型变量,结果如下
- long(1) refcount(2)
- double(0.56) refcount(2)
- string(6) "string" refcount(2)
- array(1) refcount(2){
- [1]=>
- long(1) refcount(1)
- }
- object(class1)#1 (1) refcount(2){
- ["member"]=>
- long(1) refcount(1)
- }
- resource(4) of type (stream) refcount(2)
分析绘制整个存储结构如下
对照此图就可以知道PHP各种类型的变量在内存中存储结构和用户变量如何跟内存结构挂钩,了解了这些是下一篇博文关于PHP引用详解的基础。期待下一篇PHP的赋值行为详解吧。
PHP变量存储结构的更多相关文章
- 深入PHP变量存储结构 标签: PHP存储
1.深入PHP变量存储结构 标签: PHP存储 分类: 编程语言(10) 首先声明,我并没有去读PHP的源码,只是对于PHP的有时候诡异的表现感兴趣,找了一下开发人员laruence的博客结合PH ...
- 深入理解PHP内核(五)变量及数据类型-变量的结构和类型
原文链接:http://www.orlion.ga/238/ 编程语言的类型可以分为强类型和弱类型两种,PHP是弱类型语言,但是C语言是强类型语言.在官网PHP实现内部,所有变量使用同一种数据结构(z ...
- 队列的存储结构和常见操作(c 语言实现)
一.队列(queue) 队列和栈一样,在实际程序的算法设计和计算机一些其他分支里,都有很多重要的应用,比如计算机操作系统对进程 or 作业的优先级调度算法,对离散事件的模拟算法,还有计算机主机和外部设 ...
- Oracle使用%rowtype变量存储一行数据
在Oracle中,%rowtype是用来存储一行数据的 语法: rowType_name table_name%rowtype rowType_name :变量名 table_name:指定的表名 具 ...
- (续)一个demo弄清楚位图在内存中的存储结构
本来续---数字图像处理之位图在计算机中的存储结构一文,通过参考别人的代码,进行修改和测试终于成功运行. 该实例未使用任何API和相关类,相信如果对此实例能够完全理解那么将有进一步进行数字图像处理的能 ...
- PostgreSQL的存储系统二:REDOLOG文件存储结构二
REDOLOG文件里的用户数据和数据文件里的用户数据存储结构相同 几个月前同事给台湾一家公司培训<pg9 ad admin>时,有个学员提及WAL里记录的内容为Query时的SQL语句(比 ...
- PHP内核变量存储
PHP作为一门弱类型语言,其变量类型可任意改变.而C作为PHP的底层实现,是通过结构及联合来实现PHP变量的弱类型特性的.在PHP源码中,Zend/zend.h文件有关于PHP变量的结构定义. 01 ...
- .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 ...
- c语言的作用域、变量与结构体
一.变量的作用域 根据变量的作用域,可以分为: 1.局部变量: 1> 定义:在函数(代码块)内部定义的变量(包括函数的形参) 2> 作用域:局部变量只有在定义它的函数内部使用,其它函数不能 ...
随机推荐
- [C#] 动态指定泛型类型
前言 今天为了程序能写好看一点,一直在纠结怎么指定动态泛型, 但是想想实用性好像不太大,可是把这技术忘掉太可惜XD 还是记录下来,以防忘记 以下程序范例 类 cs 123456789101112131 ...
- [LC] 159. Longest Substring with At Most Two Distinct Characters
Given a string s , find the length of the longest substring t that contains at most 2 distinct char ...
- JS替换变量中的文字字母
var text='Hello world, Hello world'; var b= text.replace('world','zhengxiaoya'); // 找到字符串中的第一个'world ...
- 启动Tomcat报WEB-INF\lib\j2ee.jar jar not loaded异常的解决办法
今天加载工程时突然发现Tomcat报: 2010-7-1 12:11:38 org.apache.catalina.loader.WebappClassLoader validateJarFile 信 ...
- JS Style Guide_1
当你在回调函数里要使用函数表达式时,尽量使用箭头函数,比如数组中的 Map.filter.reduce等的回调函数中 [1,2,3].map((x) => { let y = x + 1; re ...
- jsp页面jstl标签库失效问题
可能是版本低的问题,启用jstl即可解决(仅供参考) <%@ page isELIgnored="false"%>
- 导致提前layout的常见情况(通过chrome浏览器自带的控制台可以看到)
1.通过js获取DOM属性 2.增/删/DOM节点 3.改变浏览器窗口大小 4.改变字体 5.激活css伪类 6.修改DOM的属性,涉及到大小.位置等(该颜色不会激活提前的layout) 7.其他js ...
- 红灯区:DevOps 建设的思考和实践
点击关注"有赞coder" 获取更多技术干货哦- 作者:费解 团队:效能改进 背景 众所周知,在丰田精益生产中,核心观念包含对人的尊重.消除浪费.持续改善,只有这样,企业才能保持良 ...
- 餐厅随评系列之四:Umu日本料理(米其林二星)
文章目录 在过去的几个月,工作和生活都极其忙碌,因此博客短暂停更了一阵子.慢慢积累下了很多素材,从近期开始恢复博客更新,不过很多内容估计得靠回忆了. 索性采取"倒叙"的方法,先从最 ...
- python语法生成器、迭代器、闭包、装饰器总结
1.生成器 生成器的创建方法: (1)通过列表生成式创建 可以通过将列表生成式的[]改成() eg: # 列表生成式 L = [ x*2 for x in range(5)] # L = [0, 2, ...