PHP7中的数据类型
PHP7中的数据类型
PHP中变量名→zval,变量值→zend_value。其变量内存是通过引用计数管理的,在PHP7中引用计数在value结构中。
变量类型:
头文件在PHP源码 /zend/zend_types.h
内部实现:
PHP通过zval这个结构体来表示一个变量,而不同类型的变量值则通过zval嵌入的一个人联合体表示,即zend_value。
zend_value是一个联合体,其代码如下:
ast、ptr、zv这些类型只给内核自己使用。
字符串:
PHP为字符串单独定义了一个结构:zend_string。在zend_value中通过str指向具体结构。
存储字符串内容的val比较特殊。
val并没有使用char*类型,字符串分配时是类似这样操作的:malloc(sizeof(zend_sting)+字符串长度),就是会多分配出一些内存来存储字符串内容,这块多出来的内存起始位置就是val。
这样做的好处可以省去一次内存分配(char*),且更有助于内存管理。
val中多出来的一个字节(结构体中为val[1]而不是val[0])用于存储存储字符串的最后一个字符"\0"。
比如$a="abc",则对应的zend_string内存结构如左图:
数组:
nTableMask:这个值在散列函数根据key的hash code银蛇元素的存储为位置时用到。nTableMask = -nTableSize 或 nTableMask = ~nTableSize+1。
nNumUsed、nNumOfElements:当删除数组元素时并不会立马从数组中删除,而是将这个元素的类型标为IS_UNDEF,只有在数组容量超限,需要扩容时才会删除。
若没有扩容,则nNumUsed将一直递增,所以其值并不是有效的元素数。nNumOfElements则是数组中有效元素的数量,所以nNumOfElements ≤ nNumUsed。
Bucket结构用力保存元素的key及value。而h是hash code:如果key是数值(及数值索引)那么它的值就是数值索引的值;如果key是字符串,那么它的值就是根据字符串key通过Time33算法计算得到的散列值。h值用来映射元素的存储位置。
数组实现:
为了实现散列表的有序性,PHP中的散列表在散列函数与元素数组之间加了一层映射表,这个映射表也是数组,大小与存储元素的数组相同。
中间映射表存储元素在实际存储的有序数组中的下标:元素按照先后顺序依次插入实际存储数组,然后将其数组下标按照散列函数散列出来的位置存储在新加的映射表中。
散列函数:根据key映射出元素的的存储位置,通常会以取模作为散列函数:key->h % nTableSize。但PHP采用另一种方式:nIndex = key->h | nTableMask。
在PHP数组的结构中并没有发现这个中间映射表,事实上,它与arData放在一起。在数组初始化时,同时分配用于存储Bucket的内存和分配相同数量的uint32_t大小的空间。然后将arData偏移到存储元素数组的位置。
中间映射表可以通过arData向前访问到。
哈希冲突:不同的key值可能计算得到相同的哈希值,在插入散列表时会发生冲突,因为映射表只能存储一个元素。
解决方法:把冲突的Bucket串成链表,即中间映射表映射出来的是一个Bucket链表,而不是一个Bucket,查找时需要遍历这个链表,逐个比较key,从而找到目标元素。
HashTable会记录与它冲突的元素在arData数组中的存储位置。
在设置映射值时,发现中间映射表中要设置的位置已经被之前插入的元素占用了(值不等于初始化的-1),那么会把已经存在的值保存到新插入的Bucket中(即c插入后u2.next=0),然后将映射表中的值更新为新Bucket的存储位置(即映射表中的值:2)。
引用:
引用是一种指向其他类型的结构,类似C语言中指针的概念。当修改引用类型的变量时,其修改将反应到实际引用的变量上。
在PHP中通过&操作符生成一个引用变量,比如$b = &$a,执行时首先为&操作的变量分配一个zend_reference结构,这个结构就是引用类型的结构体,它内嵌了一个zval,此zval的value指向原来zval的value,然后将原zval的类型修改为IS_REFERENCE,原zval的value指向新创建的zend_reference结构。
例子:
$a = date("Y-m"); $b = &$a;
$a为字符串,通过&$a将其转化为引用类型并赋值给了$b,转换后的$a的类型由IS_STRING变为IS_REFERENCE,$a的value也转变为zend_reference结构,这个结构指向原来的字符串。
$a、$b间接指向了实际的value值。
使用引用时需要注意,引用只能通过&产生,不能通过赋值传递。
如上面的例子,再把$b赋值给其他变量,那么传递给新变量的value将是实际引用的值,而不是引用本身。
$a = date("Y-m"); $b = &$a; $c = $b; //如果想让$c也引用指向$a/$b引用的值,则:$c = &$b
低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
Unity跨平台的机制原理
首先需要了解的是,Unity3D的C#基础脚本模块是通过Mono来实现的。 什么是Mono? 参考下百度百科:Mono是一个由Novell公司(由Xamarin发起)主持的项目,并由Miguel de lcaza领导的,一个致力于开创.NET在Linux上使用的开源工程。它包含了一个C#语言的编译器,一个CLR的Runtime,和一组类库,并实现了 ADO NET和ASP NET。 它基于CIL和C#的ECMA标准,提供了了微软.Net FrameWork的另一种实现。 Mono主要有以下部分组成: C#编译器——mcs。(最新的Mono版本已经可以支持C#5.0,但Unity3D的Mono版本仍然停留在2.0+阶段(支持c#3.0),所以C#的一些新功能无法在unity中使用) 运行时:即时编译器JIT(后文会介绍)。以及GC,类库加载器等等。 基础类库(BCL)。 Mono类库。提供了超出微软.NET的一些类,提供了许多额外功能,主要是用于构建其他操作系统上的应用。 下面进入正题: Mono和Unity Unity引擎本身是由C++写出的,只不过Mono被嵌入到了Unity当中,为...
- 下一篇
Dubbo Mesh 在闲鱼生产环境中的落地实践
本文作者至简曾在 2018 QCon 上海站以《Service Mesh 的本质、价值和应用探索》为题做了一次分享,其中谈到了 Dubbo Mesh 的整体发展思路是“借力开源、反哺开源”,也讲到了 Service Mesh 在阿里巴巴的发路径将经历以下三大阶段: 撬动 做透价值渗透 实现技术换代 Dubbo Mesh 在闲鱼生产环境的落地,分享的是以多语言为撬动点的阶段性总结。 文章首发于「QCon」,阿里巴巴中间件授权转载。 闲鱼场景的特点 闲鱼采用的编程语言是 Dart,思路是通过 Flutter 和 Dart 实现 iOS、Android 两个客户端以及 Dart 服务端,以“三端一体”的思路去探索多端融合的高效软件开发模式。更多细节请参考作者同事陈新新在 2018 QCon 上海站的主题分享《Flutter & Dart 三端
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- Linux系统CentOS6、CentOS7手动修改IP地址
- SpringBoot2初体验,简单认识spring boot2并且搭建基础工程
- SpringBoot2全家桶,快速入门学习开发网站教程
- CentOS8编译安装MySQL8.0.19
- CentOS7,CentOS8安装Elasticsearch6.8.6
- SpringBoot2整合Redis,开启缓存,提高访问速度
- Red5直播服务器,属于Java语言的直播服务器
- CentOS6,CentOS7官方镜像安装Oracle11G
- Windows10,CentOS7,CentOS8安装Nodejs环境
- Springboot2将连接池hikari替换为druid,体验最强大的数据库连接池