Web笔记··By/蜜汁炒酸奶

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

前言

本周收到的是一篇关于php内存中对象和引用相关的内容,篇幅短小,希望能帮助各位。

原文Introduction to Objects and References in PHP Memory 作者: AGUSTIN VILLALBA

文章正文

我首次起草这篇文章是在备战我的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();
1

当执行上述语句时,变量$在内存中被创建,一个Foo 类型的对象在内存中被创建,同时一个条目被添加到符号表,表明变量$“引用”(或与之相关或指向,或者无论你想如何称呼它)Foo对象,但它本身不是一个指向该对象的指针。在概念上,我们有这样的例子: PHP内存中的对象和引用简介 突击测验:如果我们执行此操作会发生什么?

$b = $a;
1

并不是说 $b 成为了$a的引用;我们也不能说$b 是$a的拷贝。真正发生的是我们在内存中创建了一个新的变量$b,然后在符号表中添加了一个新的条目,表明变量$b也引用了和$a同样的Foo类型对象。所以,在视觉上,我们有一些类似于在这个例子中显示的东西: PHP内存中的对象和引用简介 现在,如果我们执行:

$c = &$a;
1

我们将在内存中创建第三个变量$c ,但是在符号表中没有$c 的一个新条目。相反,在符号表中,它被记录为$c 是$a 的别名,因此它的行为是一样的,但是$c 不是指向$a 的指针——不像在C中,它创建了一些称为指针的指针。为了可视化,我们有一些类似于该图所示的内容: PHP内存中的对象和引用简介 一旦我们要修改这三个变量的值(即写入一个新的值),PHP将不得不在内存中创建一个新的z_val结构,以分离变量$b$a/$c的内容,这样它们就可以独立地修改,而不会影响到其他的值。因此,如果我们将以下代码添加到前面的脚本中:

$b = new Bar();
1

在内存中,我们将有一个如下图所示的情况: PHP内存中的对象和引用简介 现在我们来考虑一个更完整的例子:

<?php

class 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 table

echo "$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 collector

echo "$b = ";var_dump($b);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39

通过执行上述脚本生成的输出是:

$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
1
2
3
4
5
6
7
8
9
10
11

PHP垃圾收集

最后,让我们看看PHP垃圾回收是如何工作的,因为它是在5.3版本中引入的。当PHP符号表中没有对该对象的引用时,PHP内存中的对象或变量将被PHP垃圾收集器删除。也就是说,从创建时间开始,PHP会维护对象的引用计数器,以便在脚本PHP执行期间,计数器根据“指向”的变量递增和减少引用计数器。一旦引用计数达到0(即,没有引用该对象,因此它不被使用),PHP将该对象标记为可移动的,以便在下一次PHP垃圾回收器中,它将从内存中删除,释放该空间以便重新使用。如果您想更详细地了解PHP垃圾回收的工作原理,请阅读这个文件。

最后的想法

我希望我已经阐明了PHP如何处理内存中的对象和变量,以及它如何“选择”应该由PHP垃圾收集器删除的对象。既然您已经了解了PHP如何在内存中管理变量和对象,那么请拿起您的笔记本,开始尝试一些代码来证明您已经学到了什么。试着使用变量和引用。另外,尝试改变一个变量的值会影响另一个引用它的值。这里有一个问题:在执行下面的代码后,$a和$b的值是多少?

$a = '1';
$b = &$a;
$b = "2$b";
1
2
3

如果您有兴趣阅读有关PHP性能特征的更多信息,请参阅Toptaler Vilson Duka的这篇文章。

了解基础知识

[toggle hide=“yes” title=“什么是PHP中的引用?” color=“”] PHP中,引用是允许两个不同变量读取和写入单个值的“别名”。 [/toggle] [toggle hide=“yes” title=“PHP垃圾收集如何工作?” color=“”] 从创建时间开始,PHP会保留对对象的引用次数。当符号表中没有对该对象的引用时,PHP垃圾回收器会将其删除。 [/toggle] [toggle hide=“yes” title=“如何存储PHP内存引用?” color=“”] PHP内存引用存储在名为符号表的键值存储中。 [/toggle]

预览
Loading comments...
0 条评论

暂无数据

example
预览