当前位置: 首页 > 后端技术 > PHP

彻底理解PHP中引用的概念

时间:2023-03-29 23:25:36 PHP

我们之前其实写过几篇关于引用的文章。这次我们就来全面梳理一下PHP中都有哪些引用。它与C指针有什么区别,使用时要注意什么。什么是引用?在PHP中引用意味着访问具有不同名称的相同变量内容。它不是C指针,不存储内存地址,不能进行指针操作。引用只是符号表的别名。就像Unix系统中的硬链接,Windows系统中的快捷方式。以上为官方手册中的原文。怎么说呢,引用其实和我们印象中的C里的指针不是一个概念。指针是对实内存的操作,引用是对指向这块内存的符号表的操作。还是从操作系统的快捷方式上来说,可以删除快捷方式,这是PHP的参考。而C不仅删除了快捷方式,还删除了原文件。这是C的指针操作//referencenotpointer$a=1;$b=&$a;echo$a,'===',$b,PHP_EOL;unset($b);echo$a,'===',$b,PHP_EOL;上面的代码是在PHP中,我们将$b变量指向$a作为$a的引用变量。然后$b被删除,对$a没有任何影响。#include#includeintmain(){//C中的指针和引用inta=1;整数*b=&a;printf("%i\n",a);//1空闲(b);//释放bprintf("%i\n",a);//geterror:***errorforobject0x7fff6350da08:pointerbeingfreedwasnotallocatedreturn0;}而在C中,引用指针将不起作用。我们删除b变量后,再打印a变量,会直接报错。虽然PHP底层也是用C写的,但是我们都知道C里面的指针是出了名的变态,没有一定的基础是非常容易出错的。所以PHP开发者并没有暴露C的原始指针能力,而是采用了类似Java的引用能力。这也是现代语言的一个特点。我们不需要过多关注底层能力,而是把更多的时间花在业务实现上。在数组和对象中使用引用如果复制了一个带有引用的数组,它的值不会被取消引用。将数组传递给函数也是如此。$arr1=["a","b"];$t1=&$arr1[1];$arr2=$arr1;$arr2[1]="c";var_dump($arr1);//数组(2){//[0]=>//string(1)"a"//[1]=>//&string(1)"c"//}$arr1=["a","b"];$t1=&$arr1[1];未设置($t1);//取消设置未引用$arr2=$arr1;$arr2[1]="c";var_dump($arr1);//array(2){//[0]=>//string(1)"a"//[1]=>//string(1)"b"//}这个其实挺有意思的,我们通过对比这两个例子可以看出一个问题,$t变量指向了对$arr[1]的引用。$arr2直接=这个$arr1,没有引用,那么$arr2修改了$arr2[1]的内容,$arr1对应的内容也发生了变化。如果$t变量未设置,则$arr1对应的内容不会有变化。为此,我在文档中找到了以下解释:由于PHP内部工作的特殊性,如果您引用一个数组的单个元素,然后复制该数组,无论是通过赋值还是在函数调用中按值传递,引用将被复制为数组的一部分。这意味着对任一数组中任何此类元素的更改将在另一个数组(和其他引用)中重复,即使数组具有不同的范围(例如,一个是函数内部的参数,另一个是全局的)!复制时没有引用的元素,以及复制数组后分配给其他元素的引用,将正常工作(即独立于其他数组)。不仅是数组,对象引用也会有一些有趣的问题。$o1=newstdClass();$o1->a='a';var_dump($o1);//对象(stdClass)#1(1){//["a"]=>//字符串(1)"a"//}$o2=&$o1;$o3=$o1;$o2->a='aa';var_dump($o1);//对象(stdClass)#1(1){//["a"]=>//字符串(2)"aa"//}var_dump($o3);//$o2将$a修改为'aa',$o3也变为'aa'//object(stdClass)#1(1){//["a"]=>//string(2)"aa"//}$o1->a='aaa';$o1=null;var_dump($o2);//$o2引用变为空//NULLvar_dump($o3);//$o3不仅引用而且存在,$a变成'aaa'//object(stdClass)#1(1){//["a"]=>//string(3)"aaa"//}上面的例子中有三个对象,$o1,$o2,$o3,其中$o2是对$o1的引用,$o3是直接赋值给$o1。对$o2属性的操作不仅会体现在$o1中,还会体现在$o3中。事实上,我们之前有一篇文章专门讨论这个问题。首先,对象的默认赋值是引用。其次,这个例子证明了一个引用是一个符号表的绑定。删除快捷方式对原始对象或其他快捷方式没有影响。可以参考:PHP中对象赋值是引用吗?引用的传递关于方法参数的引用传递,最重要的是要记住两点:一是如果变量在方法内部被修改,外部也会随之改变。这是引用的一个特点;另一种是只有变量,New语句,函数返回的引用三种。error_reporting(E_ALL);函数foo(&$var){$var++;echo'foo:',$var;}functionbar()//注意缺少的&{$a=5;返回$a;}foo(bar());//自PHP5.0.5起致命错误,自PHP5.1.1起严格模式错误//自PHP7.0起注意消息,注意:只有变量应通过引用传递foo($a=5);//表达式,不是变量,注意:只有变量应该通过引用传递//foo(5);//导致致命错误!5是常数!///////////////////////////////正确的传递类型$a=5;foo($一);//变量函数&baz(){$a=5;返回$a;}foo(baz());//从函数返回的引用functionfoo1(&$var){print_r($var);}foo1(newstdClass());//newexpressionreferencedreturnreferenced返回不是一个经常使用的能力。文档中的原文是:Don'tusereturnreferencestoincreaseperformance,theengineissmartenoughtooptimizeitself.仅在有充分的技术理由时才返回引用!$a=1;function&test(){全局$a;返回$a;}$b=&test($a);$b=2;echo$a,PHP_EOL;当你想返回一个引用变量时,一定要在方法定义和方法调用时都使用&符号。这是一个需要注意的点。当其他地方修改原始变量值或修改返回变量值时,会影响所有调用此值的地方。所以引用的返回是比较危险的,因为你不知道这个值可能在何时何地被修改了,bug排查起来会非常困难。引用的解引用其实就是直接unset变量。但是一定要记住,PHP中的引用是指向的符号表,对原来的真实值没有影响,所以即使原变量被unset,也不会影响其他引用赋值的变量!!$a=1;$b=&$a;$c=&$b;$b=2;echo'定义引用后:',$a,'===',$b,'===',$c,PHP_EOL;unset($b);$b=3;echo'取消设置$b不影响$a,$c:',$a,'===',$b,'===',$c,PHP_EOL;$b=&$a;unset($a);echo'取消$a,不影响$b,$c:',$a,'===',$b,'===',$c,PHP_EOL;//定义引用后:2===2===2//取消对$b的引用:2===3===2//取消$a,不影响$c:===3===2$a=1;$b=&$a;$c=&$b;//$a,$b,$c引用相同的内容'1'$a=NULL;//Allvariables$a,$bor$careunsetecho'Allreferencesareempty:',$a,'===',$b,'===',$c,PHP_EOL;对参考文献的更详尽的解释。只要您记住它的定义,对PHP的引用就非常容易理解。最直观的方法是将其用作操作系统的快捷方式。它并不像我们想象的那么难。和C指针相比,真的只是娃娃级别,多练习多复习自然就能掌握好!测试代码:https://github.com/zhangyue0503/dev-blog/blob/master/php/202002/source/%E5%BD%BB%E5%BA%95%E6%90%9E%E6%98%8E%E7%99%BDPHP%E7%9A%84%E4%B8%AD%E5%BC%95%E7%94%A8%E7%9A%84%E6%A6%82%E5%BF%B5。PHP参考文档:https://www.php.net/manual/zh/language.references.whatare.phphttps://www.php.net/manual/zh/language.references.whatdo.phphttps://www.php.net/manual/zh/language.references.arent.phphttps://www.php.net/manual/zh/language.references.pass.phphttps://www.php.net/manual/zh/language。references.return.phphttps://www.php.net/manual/zh/language.references.unset.phphttps://www.php.net/manual/zh/language.references.spot.php===========各媒体平台均可搜索【硬核项目经理】

最新推荐
猜你喜欢