基本上,变量在 PHP 中有两种工作方式...
除了对象之外的所有东西:
- 按值分配(这意味着如果您执行
$a = $b,则会发生副本。
- 可以通过
$a = &$b 实现引用(注意引用运算符对变量进行操作,而不是赋值运算符,因为您可以在其他地方使用它)...
- 副本使用写时复制技术。因此,如果您执行
$a = $b,则没有该变量的内存副本。但是,如果您随后执行$a = 5;,则内存将被复制并覆盖。
对于对象:
- 通过对象引用分配。它与引用的普通变量并不完全相同(我稍后会解释原因)。
- 可以通过
$a = clone $b实现按值复制。
- 引用可以通过
$a = &$b实现,但要注意这与对象无关。您将$a 变量绑定到$b 变量。它是否是一个对象并不重要。
那么,为什么对象的赋值不是真正的引用?如果你这样做会发生什么:
$a = new stdclass();
$b = $a;
$a = 4;
$b 是什么?嗯,是stdclass...那是因为它不是写变量的引用,而是对象的引用...
$a = new stdclass();
$a->foo = 'bar';
$b = $a;
$b->foo = 'baz';
$a->foo 是什么?这是baz。那是因为当您执行$b = $a 时,您是在告诉 PHP 使用相同的对象实例(因此是对象引用)。请注意,$a 和 $b 不是同一个变量,但它们都引用同一个对象。
一种思考方式是将所有存储对象的变量视为存储指向该对象的指针。所以这个物体住在别的地方。当您分配 $a = $b 其中 $b 是一个对象时,您所做的就是复制该指针。实际变量仍然是不相交的。但是当您执行$a = &$b 时,您将在$a 中存储一个指向$b 的指针。现在,当您操作$a 时,它会将指针链级联到基础对象。当您使用 clone 运算符时,您是在告诉 PHP 复制现有对象,并创建一个具有相同状态的新对象...所以 clone 实际上只是按值复制变量...
所以如果你注意到了,我说过对象没有存储在实际变量中。它存储在其他地方,只有一个指针存储在变量中。因此,这意味着您可以拥有(并且经常拥有)多个指向同一个实例的变量。出于这个原因,内部对象表示包含一个refcount(只是指向它的变量数的计数)。当一个对象的 refcount 降至 0(意味着指向它的所有变量都超出范围,或者被更改为其他对象)时,它会被垃圾回收(因为它不再可访问)...
您可以在references and PHP in the docs...上阅读更多内容
免责声明:其中一些可能是对某些概念的过度简化或模糊。我的目的只是作为它们如何工作的指南,而不是对内部发生的事情的准确细分......
编辑:哦,至于“笨拙”,我认为不是。我认为它真的很有用。否则,您将在各处传递变量引用。当应用程序的一个部分中的变量影响应用程序另一部分中的另一个变量时,这可能会产生一些非常有趣的错误。不是因为它通过了,而是因为沿线某处做了参考。
一般来说,我很少使用变量引用。我很少发现真正需要他们。但我确实一直使用对象引用。我经常使用它们,我很高兴它们是默认设置。否则我需要编写一些运算符(因为& 表示变量引用,所以需要另一个来表示对象引用)。并且考虑到我很少使用clone,我想说99.9% 的用例应该使用对象引用(所以让运算符用于低频情况)...
JMHO
我还制作了一个视频来解释这些差异。看看on YouTube。