php 多个变量指向同一个引用用法分析_php技巧_脚本之家

那么,我们怎么才能让$d和$c 都指向一个引用呢? 查了下资料 如下方法
让两个变量指向同一个内存地址

简单说明一下,当传入简单变量时必须明确指明是传值方式还是传引用方式调用参数,如果要求在函数中形参的重新赋值影响到实参就需要引用方式传值,反之就直接传值就行,特别提一下,一般对象传值就行了因为一般要求改变也只是对对象成员属性进行改变很少需要改变对象赋值。

前面我们实验的对象是基本字符串,现在我们来看下类是否遵从这个规则

可以看到对于函数返回简单变类型的情况,只有函数返回的是引用,同时以引用方式调用函数时才能真正起到引用的效果。
那么为什么PHP要设计成只有函数返回的是引用同时以引用方式调用函数时才能真正起到引用的效果,这不是很麻烦吗?一切都得从根源说起--变量存储结构。
根据以上刺探结果分析绘制内存变化过程示意图如下:

php 的引用我觉得没有
java的好用,也许是这门语言本身还在发展,很多处理还没有那么方便完善。
java初去基本数据类型(int、long、byte、short、char、boolean、float、double等),两个变量赋值都是指向同一个内存地址,而且不用你特意去指定。

好了,总结一下本博文最重要的两点:对象引用表现和普通变量一样,函数返回方式和调用方式在函数返回引用中各施其职,弄懂这两点对你加深PHP的理解和写出更好的PHP程序相信都是有帮助的。

更多关于PHP相关内容感兴趣的读者可查看本站专题:《php面向对象程序设计入门教程》、《PHP数组操作技巧大全》、《PHP基本语法入门教程》、《PHP运算与运算符用法总结》、《php字符串用法总结》、《php+mysql数据库操作入门教程》及《php常见数据库操作技巧汇总》

4.函数返回引用
PHP的函数返回引用也是很多人有疑惑的地方,PHP的函数返回引用不仅在函数定义的时候要说明返回的是引用,在调用的时候也要说明以引用的方式调用,缺一不可。这里以函数返回值为简单变量的情况来测试代码,前面已经说过了对象和普通变量引用没什么差别,不过和函数参数调用一样,一般情况下也不需要返回对象引用。

";$a = "456";echo $b;/** * 运行结果如下 * 123 * 456 */?>

最开始将$a=1时,$a变量指向内存结构1,$a(内存结构1)的引用计数refcount为1,
传值方式赋值给$b后,$a(内存结构1)的引用计数refcount+1为2,由于不是引用故is_ref值为0,$a、$b指向同一内存结构,故此时$b的引用计数refcount也为2而is_ref为0,
当$b赋值为2时,检查是否为引用is_ref为0且引用计数refcount>1故新建一个内存结构2其值为2,$b指向这个内存结构,$b的的引用计数refcount为1而is_ref为0,$a的引用计数refcount-1为1而is_ref为0;

多个变量指向同一个引用有什么好处?
节约了内存空间,多个变量指向同一个内存地址,在调用的时候多个变量都是指向的同一个内存地址。

<?php //测试变量传递 function changeByValue($a) { $a = 1; } function changeByRef(&$a) { $a = 1; } $a = 2; echo '$a before pass to changeByValue='.$a."\n"; changeByValue($a); echo '$a after pass to changeByValue='.$a."\n"; $a = 2; echo '$a before pass to changeByRef='.$a."\n"; changeByRef($a); echo '$a after pass to changeByRef='.$a."\n"; //测试对象传递 class class1 { public $a; function __construct() { $this->a = 1; } } class class2 { public $a; function __construct() { $this->a = 2; } } function changeByValueClass(class1 $a) { $a->a = 3; global $object1,$object2; echo '此时还没有对对象重新赋值,只是操作对象属性'."\n"; echo '$a->a='.$a->a."\t".'$object1->a='.$object1->a."\t".'$a属于类'.get_class($a)."\t".'$obejct1属于类'.get_class($object1)."\n"; echo '此时对对象重新赋值'."\n"; $a = $object2; echo '$a->a='.$a->a."\t".'$object1->a='.$object1->a."\t".'$a属于类'.get_class($a)."\t".'$obejct1属于类'.get_class($object1)."\n"; } function changeByRefClass(class1 &$a) { $a->a = 4; global $object1,$object2; echo '此时还没有对对象重新赋值,只是操作对象属性'."\n"; echo '$a->a='.$a->a."\t".'$object1->a='.$object1->a."\t".'$a属于类'.get_class($a)."\t".'$obejct1属于类'.get_class($object1)."\n"; echo '此时对对象重新赋值'."\n"; $a = $object2; echo '$a->a='.$a->a."\t".'$object1->a='.$object1->a."\t".'$a属于类'.get_class($a)."\t".'$obejct1属于类'.get_class($object1)."\n"; } $object1 = new class1; $object2 = new class2; changeByValueClass($object1); changeByRefClass($object1); ?> $a before pass to changeByValue=2 $a after pass to changeByValue=2 $a before pass to changeByRef=2 $a after pass to changeByRef=1 此时还没有对对象重新赋值,只是操作对象属性 $a->a=3 $object1->a=3 $a属于类class1 $obejct1属于类class1 此时对对象重新赋值 $a->a=2 $object1->a=3 $a属于类class2 $obejct1属于类class1 此时还没有对对象重新赋值,只是操作对象属性 $a->a=4 $object1->a=4 $a属于类class1 $obejct1属于类class1 此时对对象重新赋值 $a->a=2 $object1->a=2 $a属于类class2 $obejct1属于类class2 

多个变量指向同一个引用的缺点
要注意使用安全,即是由于多个变量都是指向的同一个内存地址,其中一个变量更改了某个属性,其它的变量调用的时候都是用的已经更改的实例。

image.png

demo . "";$demo1->demo = "bbbb";echo $demo2->demo . "";/** * 运行结果 * aaaa * bbbb */?>

图片 1

我更改了一下变量的名字。方便测试发现区别。在这里我们可以看到 $b=&$a
其中&符号的作用就是让$b
指向的是$a的内存区域,而不是重新开辟一个区域。所以当更改$a的值的时候$b也会随着变化。

图片 2

我这里并没有&符号指定$demo2必须指向$demo1
的内存区域,所以关于类,当一个实例变量赋值给另一个变量的时候默认就是两个变量指向同一个引用;

<?php class class1 { public $a; function __construct() { $this->a = 1; } } class class2 { public $a; function __construct() { $this->a = 2; } } $object1 = new class1; $object2 = new class2; $a = $object1; $b = $a; echo '$a->a='.$a->a."\t".'$b->a='.$b->a."\t".'$a属于类'.get_class($a)."\t".'$b属于类'.get_class($b)."\n"; $b->a = 3; echo '$a->a='.$a->a."\t".'$b->a='.$b->a."\t".'$a属于类'.get_class($a)."\t".'$b属于类'.get_class($b)."\n"; $b = $object2; echo '$a->a='.$a->a."\t".'$b->a='.$b->a."\t".'$a属于类'.get_class($a)."\t".'$b属于类'.get_class($b)."\n"; echo "\n"; $c = $object1; $d = &$c; echo '$c->a='.$c->a."\t".'$d->a='.$d->a."\t".'$c属于类'.get_class($c)."\t".'$d属于类'.get_class($d)."\n"; $d->a = 4; echo '$c->a='.$c->a."\t".'$d->a='.$d->a."\t".'$c属于类'.get_class($c)."\t".'$d属于类'.get_class($d)."\n"; $d = $object2; echo '$c->a='.$c->a."\t".'$d->a='.$d->a."\t".'$c属于类'.get_class($c)."\t".'$d属于类'.get_class($d)."\n"; ?> $a->a=1 $b->a=1 $a属于类class1 $b属于类class1 $a->a=3 $b->a=3 $a属于类class1 $b属于类class1 $a->a=3 $b->a=2 $a属于类class1 $b属于类class2$c->a=3 $d->a=3 $c属于类class1 $d属于类class1 $c->a=4 $d->a=4 $c属于类class1 $d属于类class1 $c->a=2 $d->a=2 $c属于类class2 $d属于类class2 

引用是什么?
引用就是多个变量指向同一个内存区域地址。如我们经常用的实例一个类,就是内存中开辟了一个区域存储实例的类,实例赋值给变量就是让这个变量指向这个内存区域。

最开始将$c=1时,$c变量指向内存结构1,$c(内存结构1)的引用计数refcount为1,
引用方式赋值为$d后,由于是引用故is_ref值为1,$c(内存结构1)的引用计数refcount设为0,$c、$d指向同一内存结构,故此时$d的引用计数refcount也为0而is_ref为1,
当$d赋值为2时,检查是否为引用is_ref为1,不会新建一个内存结构,只是将原来$a指向的内存结构的值改为2,其他不变。

相关文章

Comment ()
评论是一种美德,说点什么吧,否则我会恨你的。。。