PHP变量在内存中的存储方式
原文:http://www.phppan.com/tag/refcount/
每门计算机语言都需要一些容器来保存变量数据。在一些语言当中,变量都有特定的类型,如字符串,数组,对象等等。比如C和Pascal就属于这种。 而PHP则没有这样的类型。在PHP中,一个变量在某一行是字符串,可能到下一行就变成了数字。变量可以经常在不同的类型间轻易的转化,甚至是自动的转 换。PHP之所以成为一个简单并且强大的语言,很大一部分的原因是它拥有弱类型的变量。但是有些时候这也会带来一些有趣的问题。
在PHP内部,变量是存储在一个叫做zval的容器中。它不仅仅包含变量的值,也包含变量的类型。Python和PHP类似,也有一个标签标记变量类型。变量容器中包含一些Zend引擎用来区分是否引用的字段。同时它也包含这个值的引用计数。
变量存储在一个相当于关联数组的符号表中。这个数组以变量名为key,并且指向包含了这些变量的容器。如下图所示:
引用计数
PHP试着在变量拷贝(如 $a = $b )的时候变得聪明些。“=”也称为赋值操作符。当进行赋值操作时,Zend引擎不会创建一个新的变量窗口,而是增大变量窗口的 refcount 字段,你可以想象一下,当这个变量是一个巨大的字符串或一个巨大 的数组时,这将节约多少的内存。如下图所示:
第一步: 变量a,包含文本”this is”。默认情况下,引用计数等于1
第二步:将变量$a赋值给$b和$c。这里没有新的变量容器生成,仅仅是每次在变量赋值操作时将refcount加1。因为这里执行了两次赋值操作,所以refcount最后会变成3。
现在,也许你很想知道当变量$c改变时将发生什么。根据refcount的值的不同,它会有两种不同的处理方式。如果 refcount等于1,这个变量容器将更新它的值(也许同时会更新它的类型)。如果refcount大于1,将创建一个包含了新值(和类型)的变量容 器。如图2所示的第三步,$a变量所在的变量容器的refcount值被减去一,现在refcount的值是2,而新创建的容器的refcount的值为 1。当对一个变量使用unset函数时,这个变量所在的容器的refcount值将减去一,如图第4步所示。如果refcount的值少于1,Zend引 擎将翻译这个变量容器,如图第5步所示。
传递变量给函数(Passing Variables to Functions)
除了所有脚本共用的全局符号表以外,每个用户定义的函数在调用时都会创建一个属于自己的符号表,用来存放它自己的变量。当一个函数被调用后,Zend引擎 就会创建一个这样的符号表,当这个函数返回时这个函数表就会被释放。一个函数要么通过return语句返回,要么因为函数结束而返回(译者注:无返回的函 数默认会返回NULL)。如下图所示:
图3详细介绍了变量是如何传递给函数的。
第一步,我们将”thisis”赋给变量$a,然后我们将这个变量传递do_something()函数的$s变量。
第二步,你可以看到这与变量赋值的操作是一样的(与我们在前一小节提到的$b = $a类似),只是其存储在不同的符号表(函数符号表),并且引用计数加2,而不是加1。原因是函数栈也包含了这个变量容器的引用。
第三步,当我们赋新值给变量$s,原变量容器的refcount减1,并且创建一个包含了新值的变量容器。
第四步,我们通过return语句返回一个变量。返回的变量从全局符号表中获取一个实体并将其refcount的值增加1.当函数结束时,函数的符 号表将被销毁。在销毁的过程中,Zend引擎将遍历符号表中的每个变量,并将其refcount的值减少。当变量容器的refount的值变为0,这个变 量容器将会被销毁。如你所见,由于 PHP的引用计数机制,变量容器不是以拷贝的方式从函数返回。如果变量$s在第三步时没有被修改,则变量$a和$b将一直指向相同的变量容器(这个容器的 refcount为2)。在这种情况下,语句$a = “this is”将不会创建变量容器的副本。
英文原文地址:http://derickrethans.nl/files/phparch-php-variables-article.pdf
PHP变量在内存中的存储方式的更多相关文章
- <转载>浅谈C/C++的浮点数在内存中的存储方式
C/C++浮点数在内存中的存储方式 任何数据在内存中都是以二进制的形式存储的,例如一个short型数据1156,其二进制表示形式为00000100 10000100.则在Intel CPU架构的系统中 ...
- C语言中浮点数在内存中的存储方式
关于多字节数据类型在内存中的存储问题 //////////////////////////////////////////////////////////////// int ,short 各自是4. ...
- QList介绍(QList比QVector更快,这是由它们在内存中的存储方式决定的。QStringList是在QList的基础上针对字符串提供额外的函数。at()操作比操作符[]更快,因为它不需要深度复制)非常实用
FROM:http://apps.hi.baidu.com/share/detail/33517814 今天做项目时,需要用到QList来存储一组点.为此,我对QList类的说明进行了如下翻译. QL ...
- Java变量在内存中的存储
目录 Java变量在内存中的存储 成员变量 局部变量 总结 Java变量在内存中的存储 以下探究成员变量和局部变量在内存中的存储情况. package com.my.pac04; /** * @aut ...
- Float在内存中的存储方式及IEC61131处理
Float在内存中的存储方式及IEC61131处理 1,fp32(32bits float)类型数据在存储器中占用4Bytes存储,且遵循IEEE-754标准: 一个浮点数分三部分组成: 符号位s(1 ...
- 数据在内存中的存储方式( Big Endian和Little Endian的区别 )(x86系列则采用little endian方式存储数据)
https://www.cnblogs.com/renyuan/archive/2013/05/26/3099766.html 1.故事的起源 “endian”这个词出自<格列佛游记>.小 ...
- float和double在内存中的存储方式
本文转载于:http://wenku.baidu.com/link?url=ARfMiXVHCwCZJcqfA1gfeVkMOj9RkLlR9fIexbgs9gDdV8rIS48A1_xe1y6YgX ...
- C++成员函数在内存中的存储方式
用类去定义对象时,系统会为每一个对象分配存储空间.如果一个类包括了数据和函数,要分别为数据和函数的代码分配存储空间.按理说,如果用同一个类定义了10个对象,那么就需要分别为10个对象的数据和函数代码分 ...
- python中变量在内存中的存储与地址关系解析、浅度/深度copy、值传递、引用传递
---恢复内容开始--- 1.变量.地址 变量的实现方式有:引用语义.值语义 python语言中变量的实现方式就是引用语义,在变量里面保存的是值(对象)的引用(值所在处内存空间的地址).采用这种方式, ...
随机推荐
- BZOJ2683 简单题(CDQ分治)
传送门 之前听别人说CDQ分治不难学,今天才知道果真如此.之前一直为自己想不到CDQ的方法二很不爽,今天终于是想出来了一道了,太弱-- cdq分治主要就是把整段区间分成两半,然后用左区间的值去更新右区 ...
- C++是一把很奇怪的刀
C++是一把很奇怪的刀,首尾都是刀刃.用刀能出什么,还是要看拿刀的人.
- php小trick
1.unset函数是注销变量函数2.mysql 绕过截断单引号 (1)(php单引号不解析,双引号解析)$query='select * from flag where user=\''.$user[ ...
- 4..一起来学hibernate之Session详解
后续... 后续... 后续... 后续... 后续... 后续... 后续... 后续... 后续... 后续... 后续... 后续... 后续... 后续... 后续...
- Python之*args,**kw
p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Menlo; color: #021ca1; background-color: #8e352 ...
- [ASE]sprint2 总结 & sprint3计划
第二个sprint半圆满的结束了, 经历了四周之后我们将整个的框架搭建好,并且能够正常的游戏对战,破坏场景,聊天…… 但是正如老师所述,缺乏亮点. 不过大家都是第一次做,完全把他当成一个工程来一点一点 ...
- How and Where Concurrent Asynchronous I/O with ASP.NET Web API 对异步编程分析的非常的好
How and Where Concurrent Asynchronous I/O with ASP.NET Web API http://www.tugberkugurlu.com/archive/ ...
- smartroute简单集成集群聊天通讯
在制定一个规模比较多大的聊天应用时,往往需要制定部署多个应用服务,其一可以保障服务的可靠性,其二可以增加用户负载量.但制定这样一种应用体系是一件复杂的事情,毕竟同一群体的用户实际上会在不同的服务器接入 ...
- 从现在开始,使用简单优雅的validata.js
表单验证,是后台开发中万年不变的话题,在经历许多实战之后发现 使用优雅便捷的validate.js实现验证实在是一件非常愉悦的事情 <form data-validate> Enter: ...
- 【C语言学习】《C Primer Plus》第10章 数组和指针
学习总结 1.数组初始化方式: int a[]={1,2,3} int a[SIZE]={1,2,3} //SIZE是宏定义,数组初始化个数不能大于SIZE,否则报错:当个数小 //SIZE,自动补0 ...