PHP基础终极版-面试大全 深度理解变量的传值和引用
Posted huidaoli
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了PHP基础终极版-面试大全 深度理解变量的传值和引用相关的知识,希望对你有一定的参考价值。
php基础终极版-面试大全
提示:本文章为系列文章,喜欢的请一键三连
本文:(一)深度理解变量的传值和引用
提示:有任何问题请在评论区留言,谢谢
文章目录
前言
本文基础学习内容:
如何深度全面的理解PHP中的变量、及变量的传值和引用知识点,让你在工作中快速上手,成为技术强人,在面试中快速超越他人拿到offer。
提示:如果你正在面试,或在工作中遇到问题,可以来为自己加油,一起深度学下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,将创建一个包含了新值(和类型)的变量容器。如上图所示的第三步,$a变量所在的变量容器的refcount值被减去1,现在refcount的值是2,而新创建的容器的refcount的值为 1。当对一个变量使用unset函数时,这个变量所在的容器的refcount值将减去1,如上图第4步所示。如果refcount的值少于1,Zend引 擎将翻译这个变量容器,如图第5步所示。
传递变量给函数
除了所有脚本共用的全局符号表以外,每个用户定义的函数在调用时都会创建一个属于自己的符号表,用来存放它自己的变量。当一个函数被调用后,Zend引擎 就会创建一个这样的符号表,当这个函数返回时这个函数表就会被释放。一个函数要么通过return语句返回,要么因为函数结束而返回(译者注:无返回的函 数默认会返回NULL)。
如下图所示:
也许你对上图有看不懂,没关系,下面来详细说下。
下面通过上图我们来详细介绍变量是如何传递给函数的。
变量传递给函数的步骤
- 第一步,我们将”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”将不会创建变量容器的副本。
二、PHP变量取值?
通过上面的了解,我们可以知道变量取值时是从变量容器中去取的。
也就是通过变量名查找堆中的内存
三、PHP变量赋值?
赋值和unset
$a = 1;
unset($a);
两种赋值的影响:
引用传值后unset被赋值的变量举例:
$a = 1;
$b = &$a;
unset($a);
dump($a); // null
dump($b); //int 1
四、PHP变量普通传值?
普通传值,传值以后,是不同的地址名称,指向不同的内存实体$a = 1;
dump($a); //int 1
$a=2;
dump($a); //int 2
五、PHP变量引用传值?
引用传值,传引用后,是不同的地址名称,但都指向同一个内存实体;改变其中一个,另外一个就也被改变引用传值举例:
$a = 1;
$b = &$a;
dump($b); //int 1
$a=2;
dump($b); //int 2
引用传值解析:
$b=&$a表示:$b找到$a指向的内存实体1,并建立$b与1的指针关系。
此时,如果$a改变指向,$b就会自动追随$a改变指向。
注意:变量名的指向是内存地址,不是另一个变量。
六、PHP两种传值的区别?
普通传值,传值以后,是不同的地址名称,指向不同的内存实体; 引用传值,传引用后,是不同的地址名称,但都指向同一个内存实体;改变其中一个,另外一个就也被改变;七、PHP变量内存管理?
PHP的内存释放是由计数器决定的内存管理原则是:
- 1, unset只是变量计数器减1,,当计数器为0的时候会触发回收。
- 2, $s=null 会直接触发回收。
解析:
在传引用的正常情况下,如果\\$a改变指向,\\$b就会自动追随\\$a改变指向。但是如果\\$a与内存的指针关系被注销,\\$b不需要做出任何变化,仍然指向原内存地址。unset($a)是delete掉$a和内存实体1的指针关系,由于内存实体1还在被另一个变量$b引用着,所以内存实体1不会被回收。所以$a没有了指向的内存地址,值就是null。$b仍然指向原内存地址。
总结
以上就是今天要讲的内容,本文仅仅简单介绍了PHP变量的传值和引用,而PHP的基础知识点非常多,大家可以一起跟随本系列文章学习更多更全面的PHP基础。
以上是关于PHP基础终极版-面试大全 深度理解变量的传值和引用的主要内容,如果未能解决你的问题,请参考以下文章