PHP内存中的对象和引用简介

本文概述

  • PHP中的对象和引用
  • PHP中没有什么参考?
  • PHP中的引用是什么?
  • PHP垃圾回收
  • 总结思想
我在学习PHP认证时首先起草了这篇文章, 以更好地了解PHP如何管理内存中的变量和对象。经过大量研究, 我意识到要找到问题的答案并不容易, 因此, 一旦完成, 我决定记录这些信息, 以便人们可以在一处找到所有信息。
在本文中, 我将讨论如何在内存中控制对象和变量引用, 因为这是一个可能引起讨论和不同意见的问题。需要考虑的一个问题是:” 默认情况下, 对象是通过引用传递还是通过PHP副本传递?” 我将首先讨论PHP中没有哪些引用。其次, 我将讨论它们是什么, 最后, 我将研究垃圾收集器在PHP中的工作方式。
当执行$ a = new Foo(); 之类的语句时, PHP如何在内存中创建对象?如今, 内存已不再像过去那样昂贵且资源有限。但是, 对于优秀的PHP开发人员而言, 了解和理解在其应用程序执行期间如何在内部管理变量和对象仍然很重要。
PHP内存中的对象和引用简介

文章图片
PHP中的对象和引用 在PHP书籍和在线文章中, 许多人说PHP默认情况下是通过引用传递对象的。还有人说, PHP中的对象是通过副本分配的。为了弄清楚哪个语句是正确的, 首先我们必须分析PHP中的引用(什么是不是)。
PHP中没有什么参考? 比知道PHP中的引用更重要的是知道它们不是什么。在PHP中, 引用不是C风格的指针。你不能像使用C指针那样对引用进行算术运算。为什么?因为与C语言不同, PHP引用不是真正的内存地址, 因为它们不是表示内存位置的数字。但是, 引用是什么?
PHP中的引用是什么? 在PHP中, 引用是” 别名” , 它允许两个不同的变量读取和写入单个值。换句话说, 它们是一种机制, 允许从名称不同的变量访问相同的值, 以使其表现为相同的变量。请记住, 在PHP中, 变量名和变量的内容是两个完全不同的东西, 它们以所谓的” 符号表” 链接在一起。因此, 当我们创建引用时, 它只是在符号表中为该变量添加了一个别名。假设我们有以下代码:
$a = new Foo();

执行上述语句时, 将在内存中创建变量$ a, 在内存中创建类型为Foo的对象, 并将条目添加到符号表中, 该条目指示变量$ a” 引用” (或与, 或指向或想要调用它的任何对象)Foo对象, 但它本身并不是指向该对象的指针。从概念上讲, 我们有类似以下插图的内容:
PHP内存中的对象和引用简介

文章图片
流行测验:如果执行此操作会怎样?
$b = $a;

不是$ b成为$ a的引用;我们也不能说$ b是$ a的副本。真正发生的是, 我们在内存中创建了一个新变量$ b, 然后在符号表中添加了一个新条目, 表明变量$ b也引用了与$ a相同的Foo对象。因此, 在视觉上, 我们具有与下图所示相似的内容:
PHP内存中的对象和引用简介

文章图片
现在, 如果我们执行:
$c = & $a;

我们将在内存中创建第三个变量$ c, 但不会在符号表中为$ c创建新的条目。而是在符号表中记录了$ c是$ a的别名, 因此它的行为相同, 但是$ c不是指向$ a的指针-与在C中不同, 后者创建了称为指针的指针。为了可视化, 我们具有与下图所示相似的内容:
PHP内存中的对象和引用简介

文章图片
【PHP内存中的对象和引用简介】一旦我们想要修改这三个变量中的任何一个的值(即, 写入一个新值), PHP将必须在内存中创建一个新的z_val结构, 以分隔变量$ b和对$ a /的内容。 $ c, 因此它们每个都可以独立修改而不会影响对方的价值。因此, 如果我们在前面的脚本中添加以下行:
$b = new Bar();

在内存中, 我们将遇到下图所示的情况:
PHP内存中的对象和引用简介

文章图片
现在, 让我们考虑一个更完整的示例:
< ?phpclass myClass { public $var; function __construct() { $this-> var = 1; }function inc() { return ++$this-> var; } }$a = new myClass(); // $a "references" a Foo object $b = $a; //b also references the same Foo object as a //($a) == ($b) == < id> of Foo object, but a and b are different entries in symbols tableecho "$a = "; var_dump($a); echo "$b = "; var_dump($b); $c = & $a; //$c is an alias of $a //($a, $c) == < id> of Foo object, c is an alias of a in the symbols table echo "$c = "; var_dump($c); $a = NULL; //The entry in the symbols table which links "$a" with Foo object is removed //Since that entry was removed, $c is not related to Foo anymore //Anyway, Foo still exists in memory and it is still linked by $b echo "$a = "; var_dump($a); echo "$b = "; var_dump($b); echo "$c = "; var_dump($c); echo "$b-> var: ".$b-> inc(); echo "$b-> var: ".$b-> inc(); $b = NULL; //The entry in the symbols table which links "$b" with the Foo object is removed //There are no more entries in the symbols table linked to Foo, //So, Foo is not referenced anymore and can be deleted by the garbage collectorecho "$b = "; var_dump($b);

上面脚本的实现产生的输出是:
$a = object(myClass)#1 (1) { ["var"]=> int(1) } $b = object(myClass)#1 (1) { ["var"]=> int(1) } $c = object(myClass)#1 (1) { ["var"]=> int(1) } $a = NULL $b = object(myClass)#1 (1) { ["var"]=> int(1) } $c = NULL $b-> var: 2 $b-> var: 3$b = NULL

PHP垃圾回收 最后, 让我们看看PHP垃圾回收的工作原理, 因为它是在5.3版中引入的。当符号表中没有对该对象的引用时, PHP垃圾收集器将删除PHP内存中的对象或变量。也就是说, PHP从创建对象开始就一直维护对象的引用计数器, 以便在脚本PHP执行期间, 该计数器根据” 指向” 该对象的变量来递增和递减引用计数器的对象。一旦引用计数达到0(即, 没有任何东西引用该对象, 因此没有使用它), PHP将该对象标记为可移动, 以便在PHP垃圾收集器的下一次传递中, 将其从内存中删除。 , 释放该空间以供重用。如果你想更深入地了解PHP垃圾回收的工作方式, 请阅读此文档。
总结思想 我希望我已经澄清了一点, PHP如何处理内存中的对象和变量, 以及它如何” 选择” 应由PHP垃圾收集器删除的对象。
现在, 你已经了解了PHP如何在内部管理内存中的变量和对象, 抓住笔记本电脑并开始尝试一些代码以证明你学到了什么。尝试玩弄变量和引用。此外, 尝试更改变量的值如何影响引用它的另一个变量的值。这是你的问题:执行下面的代码后, $ a和$ b的值是什么?
$a = '1'; $b = & $a; $b = "2$b";

如果你有兴趣阅读有关PHP性能功能的更多信息, 请查看srcminier Vilson Duka研究员的这篇文章。

    推荐阅读