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

[InPHP]析构、作用域和引用

时间:2023-03-30 03:33:19 PHP

在写析构方法的研究代码时,遇到了一个交叉知识点导致的错误——在不同的作用域中,析构方法和引用的个数导致了不同的相同结果。前提本文假定您已经了解什么是析构函数、作用域和引用计数。关于后者,引用计数是PHP垃圾回收中的一个重要机制,很大程度上帮助PHP清理程序运行时的内存垃圾(参考:ReferenceCountingBasics-PHPDoc)。检查错误测试的代码:classA{public$var=[];公共功能__construct(){echo'__construct:'.spl_object_hash($this)。"\n";}publicfunction__destruct(){echo'__destruct:'.spl_object_hash($this);}publicfunctiontest(){thrownewException('Hello');}}$test=newA();$test->test();就是“抛出未捕获异常时析构函数是否正常执行”。结果是没有执行,OK,很稳定:__construct:0000000045f0af9e00000000494744b0Fatalerror:UncaughtException:Helloin...当我们认为事情已经结束的时候,往往会有后续。翻过的代码被公司前辈指出“你这段代码有问题,范围错误”后,我当场下去了。什么,范围?析构方法?我是不是理解错了,这不是变量的概念吗?经过我的追问,学长告诉我:把执行代码放在函数里试试。为避免文章冗长,直接上区别部分的代码,如下:classA{//同前}functiontest(){$test=newA();$测试->测试();}测试();结果如下:__construct:000000004b11d811000000006f9a75c7__destruct:000000004b11d811000000006f9a75c7Fatalerror:UncaughtException:Helloin...心态是这样的:你不执行你约定的吗?这是无望的。当场打脸,只好搞清楚“析构方法的作用域”是什么。我在搜索结果中看到了这一点:当对一个对象的所有引用都被删除或对象被显式销毁时,析构函数就会被执行。资料来源:构造函数和析构函数-PHPDoc让我们推理一下:当函数结束时,函数级范围结束,而脚本尚未结束。没有任何引用的对象实例自然可以执行析构方法;全局作用域不同,所以对象在全局作用域结束后没有机会调用析构方法。结果似乎很清楚。当然,如果我只是品尝一下,我很抱歉我的好奇心。既然想明白了这个问题,那么我们来问一下核心问题:确认:函数级作用域的结束与对象的析构方法的执行之间是否存在必然联系?新问题:调用析构方法或结束变量时谁在先?相信弄清楚以上两个问题的答案后,这篇文章就没有任何意义了。笑~问题1.函数级作用域的结束和对象的析构方法的执行有必然联系吗?很简单,我们将对象的作用域与函数解耦,我们可以反过来证明:classA{//与之前一致}$i=123;functiontest(&$i)//通过引用机制,给函数增加污染变量的范围{$test=newA();$i=$测试;//将对象实例的引用扩展到全局范围$test->test();}test($i);结果如下:__construct:0000000042a054c3000000001f53236fFatalerror:UncaughtException:Helloin...果然,当引用计数不为0时,不会调用析构函数,稳定~问题2新问题:谁调用了析构函数方法和结束变量?谁先来?这个问题有点意思,熟悉程序的朋友应该明白,遇到这种“X的某种机制什么时候触发”,应该看X的生命周期,X指代一切。经过一番查找,从《PHP7内核剖析》找到了PHP的生命周期,注意我用红圈圈出的两个地方:清理全局变量和调用析构方法,找到了。但是这时候让我困惑的问题就变成了:普通变量什么时候销毁?翻遍了PHP的生命周期和网上的文章,都没有找到想要的答案。大家都在说全局变量的销毁。普通的全局变量是弱势群体吗?直到我看到PHP手册上的例子://Useglobal$a=1;$b=2;函数Sum(){全局$a,$b;$b=$a+$b;}总和();回声$b;原来全局作用域内的普通变量=全局变量,这个结论真是把我看秃了。最后总结一下:当实例的引用为0时,会进入析构阶段,此时会启用析构函数;当对象的实例在全局范围内时,该变量将在全局变量销毁事件中被销毁,在此之前,全局变量至少有一个引用计数;对析构函数的调用发生在全局变量被销毁之前。当析构函数的调用钩子检查“引用号”时,全局实例自然不能触发这个事件。至于为什么会犯这样的错误,有两个原因:对PHP的生命周期理解模糊;目前尚不清楚如何定义PHP的全局变量。犯这两个错误自然是有原因的,但不管是什么原因,都无法解决在面对知识点交叉时因为知识盲点而犯的错误。下次你学东西的时候,按照官方文档。图片来源网络或水印,侵删。