资讯专栏INFORMATION COLUMN

PHP中引用传递+unset+global理解,希望大神指正

ConardLi / 3076人阅读

摘要:即产生了相当于这样的效果,所以改变的值也同时改变了的值。不要用返回引用来增加性能,引擎足够聪明来自己进行优化。只能从函数返回引用变量没别的方法。

关键是对global的误解,之前以为在函数中global变量,就是把函数外部的变量拿进函数内部使用,但似乎我错了
引用传递+unset+global理解

php的引用(就是在变量、函数、对象等前面加上&符号)
在PHP中引用的意思是:不同的名字访问同一个内存地址

1、变量的引用:PHP的引用允许你用两个变量来指向同一个内存空间
代码:

结果:

2、函数的传址调用

这里$num传递给函数的其实是$num所处的内存地址,通过在函数里改变$a的值,就可以改变$num的值了

3、函数的引用返回 —— 没太明白什么时候用
和参数传递不同,函数的引用返回必须在两个地方都用 & 符号(函数声明时、函数调用时) —— 指出返回的是一个引用,而不是通常的一个拷贝

结果:

结果:

结果:

结果:

下面解释下:
尽管函数声明方式是 function &test() 这样,但通过$a = test() 这种方式的函数调用得到的其实不是函数的引用返回,这跟普通的函数调用没有区别
PHP规定通过 $a = &test() 并且在声明函数时也使用了&,得到的才是函数的引用返回
用上面的例子来解释就是,$a = test() 这种方式调用函数,只是将函数的返回值赋给 $a 而已,而$a做任何改变都不会影响到函数中的$b

而通过 $a = &test() 方式调用函数呢(前提是声明函数时也用了&),它的作用是将 return $b 中的 $b 变量的内存地址与 $a 变量的内存地址指向了同一个地方。即产生了相当于这样的效果 ($a=&$b), 所以改变 $a 的值也同时改变了 $b 的值。所以在执行了
$a = &test();
$a = 5;
以后,$b的值也变为了5

再来个例子加深理解:
PHP里的函数的引用在定义及调用都要在函数名前加上 &

结果:

这里是为了让大家理解函数的引用返回才使用静态变量的,其实函数的引用返回多用在对象中
很多时候我们会看到这样的代码(出自 CI 框架源码):
$class =& load_class("a","b");

手册里是这么写的:引用返回用在当想用函数找到引用应该被绑定在哪一个变量上面时。不要用返回引用来增加性能,引擎足够聪明来自己进行优化。仅在有合理的技术原因时才返回引用!要返回引用,使用此语法:

和参数传递不同,这里必须在两个地方都用 & 符号——指出返回的是一个引用,而不是通常的一个拷贝,同样也指出 $myValue 是作为引用的绑定,而不是通常的赋值
如果试图这样从函数返回引用:return ($this->value);,这将不会起作用,因为在试图返回一个表达式的结果而不是一个引用的变量。只能从函数返回引用变量——没别的方法。如果代码试图返回一个动态表达式或 new 运算符的结果,自 PHP 4.4.0 和 PHP 5.1.0 起会发出一条 E_NOTICE 错误
似懂非懂?那么我们来改写一下程序吧,让它变成一个常规的函数:

结果:

现在能理解“引用返回用在当想用函数找到引用应该被绑定在哪一个变量上面时”这句话了吧,函数 &getValue() 把引用绑定在成员变量 $value 上了。正常来说,$obj = new foo; 产生的 $obj 是一个copy,它的成员变量 $value 与函数 getValue() 不存在“别名”(引用)关系(额,不太懂)

4、对象的引用

结果:

以上代码是在PHP5中的运行效果,在PHP5中对象的复制是通过引用来实现的。上列中$b=new a; $c=$b; 其实等效于$b=new a; $c=&$b; PHP5中默认就是通过引用来调用对象, 但有时你可能想建立一个对象的副本,并希望原来的对象的改变不影响到副本,为了这样的目的,PHP定义了一个特殊的方法,称为__clone
php5中对于大数组的传递,建议用 "&" 方式,毕竟节省内存空间使用

5、取消引用
重要的是删除引用的变量,当你 unset 一个引用,只是断开了变量名和内存地址之间的绑定。只是unset的变量访问不了,这并不意味着内存地址被销毁了

不会 unset $b,只是 $a

地址(引用)传递,只是多个变量指向了同一地址(内存空间)
unset一个,并不能unset掉地址空间

根据这个原理,我们来屡屡$a和$GLOBALS["a"]之间的关系
代码1:

代码2:

结果:

代码3:

结果:

根据这三段代码的结果,$a和$GLOBALS["a"]在内存中的关系肯定不是这样的

如果是这样的话,unset掉一个,另一个应该还是存在的
所以个人猜测关系应该是这样的:

其中一个是另一个的别名
关于这个问题,也问了一些人,各有个的说法,况且都牵扯到了PHP底层机制,暂且放一放,按照上面说的来理解吧

6、global

这里的$num =& $GLOBALS["num"]; $num是函数里的$num,函数里的$num指向了$GLOBALS["num"]的内存地址

global 引用
当在函数中用 global $var 声明一个变量时实际上建立了一个到全局变量的引用。也就是说和这样做是相同的:
$var =& $GLOBALS["var"];
这意味着,unset $var 不会 unset 全局变量

$this 在一个对象的方法中,永远是调用它的对象的引用

再来一个例子:

结果:

为什么会是0 5呢?
global在函数中产生一个指向函数外部变量的别名变量,而不是真的把函数外的变量拿到函数中使用
一旦改变了别名变量(函数内部的变量)的指向地址
$var2 =& $var1;
其实就是函数中$var2的引用指向了$var1的内存地址
只是函数中$var2的指向发生了变化,函数内部变量的变化只在函数的局部产生效应,在函数外部$var2的指向物理内存地址并没有变化,还是它自己,所以根本就没有改变函数外$var2的值
$GLOBALS[]确确实实调用的是函数外部的变量,函数内外始终保持一致!

结果:

7、写时拷贝
php中对于地址的指向(类似指针)功能不是由用户自己来实现的,是由Zend核心实现的,php中引用采用的是写时拷贝的原理,就是除非发生写操作,指向同一个地址的变量或者对象是不会被拷贝的
通俗的讲:
① 如果有下面的代码
$a="ABC"; $b=$a;
其实此时,$a与$b都是指向同一内存地址,而并不是$a与$b占用不同的内存
② 如果在上面的代码基础上再加上如下代码
$a="EFG";
由于$a与$b所指向的内存的数据要重新写一次了,此时Zend核心会自动判断,自动为$b产生一个$a的数据拷贝,重新申请一块内存进行存储

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/21305.html

相关文章

  • 搞定PHP面试 - 深入了解引用

    摘要:引用可以被看作是文件系统中的硬链接。如果具有引用的数组被复制,其值不会解除引用。如果试图这样从函数返回引用,将会报错,因为函数在试图返回一个表达式的结果而不是一个引用的变量。这并不意味着变量内容被销毁了。 1. 什么是引用 在 PHP 中引用是指用不同的名字访问同一个变量内容。PHP 中的变量名和变量内容是不一样的, 因此同样的内容可以有不同的名字。最接近的比喻是 Unix 的文件名和...

    fox_soyoung 评论0 收藏0
  • 关于PHP5后“默认情况下对象是通过引用传递的”思考

    摘要:中的对象传递然后说一下之后的默认情况下的对象是通过引用传递的这件事情。如此时,其实表示的并不是是的引用,和可以说是没什么关系的,有关系的是实例化类得到的对象。 首先引发这篇博文的是来源于这篇帖子:https://segmentfault.com/q/10... 经过了思考之后,我决定把回答思考变成博客做一下记录,如有不对之处,欢迎指正。 指针与引用 首先,引用和指针是不一样的,指针在...

    hosition 评论0 收藏0
  • php获取变量的状态

    摘要:销毁给定的变量函数的行为依赖于给定的变量的类型而有所不同。以上例程会输出如果在函数中一个静态变量,那么在函数内部此静态变量之前将被销毁。但是,当再次调用此函数时,此静态变量将被复原为上次被销毁之前的值。 isset() isset()-检测变量是否设置 语法: bool isset (mixed $var [,mixed $var [,$....]]) 说明: 如果var存在则返回tr...

    antz 评论0 收藏0
  • PHPglobal与$GLOBALS的区别

    摘要:是一个关联数组,每一个变量为一个元素,键名对应变量名,值对应变量的内容。之所以在全局范围内存在,是因为是一个超全局变量。 概念 单一个global是一个关键字,通常附加在变量前,用于将变量声明至全局作用域;$GLOBALS是预定义的超全局变量,把变量扔到里边的话一样可以带到全局去。 $GLOBALS 是一个关联数组,每一个变量为一个元素,键名对应变量名,值对应变量的内容。$GLOBAL...

    RaoMeng 评论0 收藏0
  • PHP 引用是个坑,请慎用

    摘要:发布时最大的变动是对象处理方式。这很容易被误解为引用,但是存储器的引用与引用是完全不同的概念。使用引用是一件不好的事情,除了引用本身不好,并且还会使性能下降这个事实外,使用引用这种方式会使得代码难以维护。 showImg(https://segmentfault.com/img/remote/1460000014082570); 去年我参加了很多次会议,其中八次会议里我进行了相关发言,...

    dockerclub 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<