摘要:对于来说,变量有全局变量和局部变量之分那么,他们都是存储到一个哈希表内了么其实不是的,变量存储也有作用域的概念。
上次跟大家讲了垃圾回收机制后,有些小伙伴对底层原理比较感兴趣,私信问我了一些关于变量的相关知识,既然大家对变量比较感兴趣,那么这次我们来系统的讲一下变量的底层原理
变量结构首先,我们还是先摆上我们的zval结构体,即php所有变量都会以zval结构体的形式实现
struct _zval_struct { union { long lval; double dval; struct { char *val; int len; } str; HashTable *ht; zend_object_value obj; } value; //变量value值 zend_uint refcount__gc; //引用计数内存中使用次数,为0删除该变量 zend_uchar type; //变量类型 zend_uchar is_ref__gc; //区分是否是引用变量,是引用为1,否则为0 };
从上面结构体内容可以看出每一个php变量都会由变量类型、value值、引用计数次数和是否是引用变量四部分组成
注:上面zval结构体是php5.3版本之后,php7版本之前的结构
变量类型看到这里,可能会有小伙伴们问我,php不是有8种数据类型吗?但是为什么对应的zvalue的value值只有5种?
原因是这样的,php出于对内存节省的考虑,所以对于一些变量类型做了复用,并没有一一对应去定义每个变量类型
下面我们看一下zvalue的每个value值所对应的变量类型
zval.value.lval => 整型、布尔型、资源 zval.value.dval => 浮点型 zval.value.str => 字符串 zval.value.*ht => 数组 zval.value.obj => 对象
看到这里大家可能会比较奇怪,布尔型和资源是怎么对应到zval.value的lval上的呢?还有,NULL呢?
布尔型就像我们会将true和false映射成0和1进行数据库存储一样,php也是这么做的。所以php发现zval的type值是布尔型时,会将布尔型转成0或1存储在zval.value的lval中
资源资源对于php来说属于一个比较特殊的变量,而php会将每个资源对应的资源标识存储在zval.value的lval中。常见的资源有:文件句柄、数据库句柄等
NULL对于NULL来说,就更好理解了,因为本身通过zval的type值即可区分,所以并没有将NULL值存储在zval的value中
变量生成php作为一门动态语言,没有先声明变量后赋值的习惯,所以都是拿来一个变量直接就进行了赋值,那么是如何实现的呢?
举例:
$name = "许铮的技术成长之路";变量容器生成
其实每次变量被常量赋值时,都会对应生成一个变量容器。刚才的例子会生成一个变量容器,容器的type是字符串类型,而value值则是许铮的技术成长之路,且此时该变量容器的ref_count会加1
变量名和变量容器关联而变量name是如何与变量容器关联起来的呢?其实也是使用了php的一个内部机制,即哈希表。每个变量的变量名和指向zval结构的指针被存储在哈希表内,以此实现了变量名到变量容器的映射
变量作用域上面我们提到了变量名和变量容器映射的概念。对于php来说,变量有全局变量和局部变量之分;那么,他们都是存储到一个哈希表内了么?
其实不是的,变量存储也有作用域的概念。全局变量被存储到了全局符号表内,而局部变量也就是指函数或对象内的变量,则被存储到了活动符号表内(每个函数或对象都多带带维护了自己的活动符号表。活动符号表的生命周期,从函数或对象被调用时开始,到调用完成时结束)
变量销毁变量销毁,分为以下几种情况:
1、手动销毁
2、垃圾回收机制销毁(引用计数清0销毁和根缓冲区满后销毁)
我们这次主要讲一下手动销毁,即unset,每次销毁时都会将符号表内的变量名和对应的zval结构进行销毁,并将对应的内存归还到php所维护的内存池内(按内存大小划分到对应内存列表中)
而对于垃圾回收机制的销毁,如果你不了解其相关原理,那么我建议你看下我之前写的文章php底层原理之垃圾回收机制
思考今天,我们从底层的角度,将变量从生成到销毁讲了一遍。对于变量的生成,我们是拿常量赋值作为示例讲解的,那么变量之间的赋值呢?是什么原理呢?且听下回分解~
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/31041.html
摘要:但是对于结构体中的和字段我们一直都没有详细介绍过,而这两个字段其实是和变量之间赋值的原理有着密切的关系的。 上周我们从底层的角度介绍了php变量从生成->常量赋值->销毁的完整生命周期(不了解的同学可以翻看一下前面的文章php底层原理之变量(一)),但是我们留了一个思考,不知道大家有答案了没,变量之间的赋值在底层又是如何实现的呢? 变量之间赋值 php变量的zval结构,我们已经介绍了...
摘要:数组是最常用的数据类型,同时容易上手也得益于其强大的数组,但是数组在中是如何实现的呢首先,我们还是先了解下相关的数据结构,为下面的内容打好基础哈希表哈希表,顾名思义,即将不同的关键字映射到不同单元的一种数据结构。 数组是PHPer最常用的数据类型,同时php容易上手也得益于其强大的数组,但是数组在php中是如何实现的呢? 首先,我们还是先了解下相关的数据结构,为下面的内容打好基础 哈希...
摘要:总结垃圾回收机制以的引用计数机制为基础以前只有该机制同时使用根缓冲区机制,当发现有存在循环引用的时,就会把其投入到根缓冲区,当根缓冲区达到配置文件中的指定数量后,就会进行垃圾回收,以此解决循环引用导致的内存泄漏问题开始引入该机制 php垃圾回收机制,对于PHPer来说是一个不陌生但是又不是很熟悉的内容。那么php是怎么实现对不需要的内存进行回收的呢? php变量的内部存储结构 首先还是...
摘要:所以想要理解更深入的同学最好查看下我之前的关于介绍变量函数的文章类的数据结构不管是普通类还是抽象类或是接口,都存放到统一的结构体中,并且在生成中间代码时,会将此类添加到全局类列表中。 对于PHPer来说,OOP是不可或缺的开发思维,但是你对php类和对象的底层实现又了解多少呢?本着知其然且知其所以然的思想,让我们一起来寻找答案~ 类的底层实现可看作是之前我们讲过的变量、函数等的知识集合...
摘要:发现挺有意思的一个问题,内存溢出导致脚本执行失败。那就一起来看个究竟吧首先查看了计划任务的从报错信息字面意思可以看出,允许的的内存已经用尽,还要试图分配内存。给你当前脚本分配的内存你已经用完了,你还想问系统要内存。 今天上午刚到公司,就有同事在公司群里反映某个计划任务出现问题了。我就怀着刨根问底的心,去查看了log。发现挺有意思的一个问题,PHP内存溢出导致脚本执行失败。那就一起来看个...
阅读 675·2021-10-14 09:42
阅读 1946·2021-09-22 15:04
阅读 1528·2019-08-30 12:44
阅读 2117·2019-08-29 13:29
阅读 2703·2019-08-29 12:51
阅读 524·2019-08-26 18:18
阅读 661·2019-08-26 13:43
阅读 2770·2019-08-26 13:38