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

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

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

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

clipboard.png

结果:函数

clipboard.png

二、函数的传址调用性能

clipboard.png

这里$num传递给函数的实际上是$num所处的内存地址,经过在函数里改变$a的值,就能够改变$num的值了优化

三、函数的引用返回 —— 没太明白何时用
和参数传递不一样,函数的引用返回必须在两个地方都用 & 符号(函数声明时、函数调用时) —— 指出返回的是一个引用,而不是一般的一个拷贝this

clipboard.png

结果:spa

clipboard.png

clipboard.png

结果:指针

clipboard.png

clipboard.png

结果:对象

clipboard.png

clipboard.png

结果:

clipboard.png

下面解释下:
尽管函数声明方式是 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里的函数的引用在定义及调用都要在函数名前加上 &

clipboard.png

结果:

clipboard.png

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

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

clipboard.png

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

clipboard.png

结果:

clipboard.png

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

四、对象的引用

clipboard.png

结果:

clipboard.png

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

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

clipboard.png

不会 unset $b,只是 $a

clipboard.png

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

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

clipboard.png

代码2:

clipboard.png

结果:

clipboard.png

代码3:

clipboard.png

结果:

clipboard.png

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

clipboard.png

若是是这样的话,unset掉一个,另外一个应该仍是存在的
因此我的猜想关系应该是这样的:

clipboard.png

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

六、global

clipboard.png

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

clipboard.png

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

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

再来一个例子:

clipboard.png

结果:

clipboard.png

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

clipboard.png

结果:

clipboard.png

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

clipboard.png

相关文章
相关标签/搜索