在 PHP 中,有人可以解释克隆与指针引用吗?

发布于 2024-09-16 22:22:39 字数 739 浏览 1 评论 0原文

首先,我了解编程和对象,但以下内容对我来说 PHP 没有多大意义。

在 PHP 中我们使用 &运算符检索对变量的引用。我将引用理解为用不同变量引用相同“事物”的一种方式。例如,如果我说

$b = 1;
$a =& $b;
$a = 3;
echo $b;

将输出 3,因为对 $a 所做的更改与对 $b 所做的更改相同。反之:

$b = 1;
$a = $b;
$a = 3;
echo $b;

应该输出1。

如果是这样的话,为什么需要clone关键字呢?在我看来,如果我设置

$obj_a = $obj_b 那么对 $obj_a 所做的更改不应影响 $obj_b, 反之$obj_a =& $obj_b 应该指向同一个对象,因此对 $obj_a 所做的更改会影响 $obj_b。

然而,在 PHP 中,$obj_a 上的某些操作似乎会影响 $obj_b,即使在没有引用运算符 ($obj_a = $obj_b) 的情况下进行分配也是如此。这给我今天在使用 DateTime 对象时带来了一个令人沮丧的问题,我最终通过基本上解决了这个问题:

$obj_a = clone $obj_b

但是我编写的大多数 php 代码似乎不需要像本例那样的显式克隆,并且没有它也可以正常工作。这是怎么回事?为什么 PHP 必须如此笨拙?

To begin with, I understand programming and objects, but the following doesn't make much sense to me in PHP.

In PHP we use the & operator to retrieve a reference to a variable. I understand a reference as being a way to refer to the same 'thing' with a different variable. If I say for example

$b = 1;
$a =& $b;
$a = 3;
echo $b;

will output 3 because changes made to $a are the same as changes made to $b. Conversely:

$b = 1;
$a = $b;
$a = 3;
echo $b;

should output 1.

If this is the case, why is the clone keyword necessary? It seems to me that if I set

$obj_a = $obj_b then changes made to $obj_a should not affect $obj_b,
conversely $obj_a =& $obj_b should be pointing to the same object so changes made to $obj_a affect $obj_b.

However it seems in PHP that certain operations on $obj_a DO affect $obj_b even if assigned without the reference operator ($obj_a = $obj_b). This caused a frustrating problem for me today while working with DateTime objects that I eventually fixed by doing basically:

$obj_a = clone $obj_b

But most of the php code I write doesn't seem to require explicit cloning like in this case and works just fine without it. What's going on here? And why does PHP have to be so clunky??

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

何以笙箫默 2024-09-23 22:22:39

基本上,变量在 PHP 中有两种工作方式...

对于除对象之外的所有内容:

  1. 按值赋值(意味着如果执行 $a = $b 则会发生复制。
  2. 可以通过执行 < code>$a = &$b (请注意,引用运算符对变量进行操作,而不是赋值运算符,因为您可以在其他地方使用它)...
  3. 副本使用写时复制技术。因此,如果您执行 $a = $b,则不会有该变量的内存副本,但如果您执行 $a = 5;,则会复制内存,并且 复制

对于对象:

  1. 通过对象引用进行赋值与普通的通过引用进行赋值不同(稍后我会解释为什么
  2. 按值 )。 >.
  3. 可以通过执行 $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(只是指向它的变量数量的计数)。当一个对象的引用计数下降到 0(意味着指向它的所有变量要么超出范围,要么更改为其他值)时,它就会被垃圾收集(因为它不再可访问)...

您可以阅读更多内容 < a href="http://php.net/manual/en/features.gc.refcounting-basics.php" rel="noreferrer">文档中的引用和 PHP...

免责声明:其中一些可能是某些概念的过度简化或模糊。我的目的只是作为它们如何工作的指南,而不是内部发生的事情的精确分解...

编辑:哦,至于这是否“笨重”,我不认为我认为是的。我认为它真的很有用。否则,变量引用就会到处传递。当应用程序一部分中的变量影响应用程序另一部分中的另一个变量时,这可能会产生一些非常有趣的错误。并不是因为它已经通过了,而是因为在整个过程中的某个地方进行了引用。

一般来说,我不太使用变量引用。我很少发现对它们的真诚需求。但我确实一直使用对象引用。我经常使用它们,因此我很高兴它们是默认值。否则我需要编写一些运算符(因为 & 表示变量引用,因此需要另一个运算符来表示对象引用)。考虑到我很少使用克隆,我想说 99.9% 的用例应该使用对象引用(因此使运算符用于较低频率的情况)...

JMHO

我也创建了一个视频来解释这些差异。 在 YouTube 上查看。

Basically, there are two ways variables work in PHP...

For everything except objects:

  1. Assignment is by value (meaning a copy occurs if you do $a = $b.
  2. Reference can be achieved by doing $a = &$b (Note the reference operator operates upon the variable, not the assignment operator, since you can use it in other places)...
  3. Copies use a copy-on-write tehnique. So if you do $a = $b, there is no memory copy of the variable. But if you then do $a = 5;, the memory is copied then and overwritten.

For objects:

  1. Assignment is by object reference. It's not really the same as normal variable by reference (I'll explain why later).
  2. Copy by value can be achieved by doing $a = clone $b.
  3. Reference can be achieved by doing $a = &$b, but beware that this has nothing to do with the object. You're binding the $a variable to the $b variable. It doesn't matter if it's an object or not.

So, why is assignment for objects not really reference? What happens if you do:

$a = new stdclass();
$b = $a;
$a = 4;

What's $b? Well, it's stdclass... That's because it's not writing a reference to the variable, but to the object...

$a = new stdclass();
$a->foo = 'bar';
$b = $a;
$b->foo = 'baz';

What's $a->foo? It's baz. That's because when you did $b = $a, you are telling PHP to use the same object instance (hence the object reference). Note that $a and $b are not the same variable, but they do both reference the same object.

One way of thinking about it, is to think of all variables which store an object as storing the pointer to that object. So the object lives somewhere else. When you assign $a = $b where $b is an object, all you're doing is copying that pointer. The actual variables are still disjoint. But when you do $a = &$b, you're storing a pointer to $b inside of $a. Now, when you manipulate $a it cascades the pointer chain to the base object. When you use the clone operator, you're telling PHP to copy the existing object, and create a new one with the same state... So clone really just does a by-value copy of the varaible...

So if you noticed, I said the object is not stored in an actual variable. It's stored somewhere else and nothing but a pointer is stored in the variable. So this means that you can have (and often do have) multiple variables pointing to the same instance. For this reason, the internal object representation contains a refcount (Simply a count of the number of variables pointing to it). When an object's refcount drops to 0 (meaning that all the variables pointing to it either go out of scope, or are changed to somethign else) it is garbaged collected (as it is no longer accessable)...

You can read more on references and PHP in the docs...

Disclaimer: Some of this may be oversimplification or blurring of certain concepts. I intended this only to be a guide to how they work, and not an exact breakdown of what goes on internally...

Edit: Oh, and as for this being "clunky", I don't think it is. I think it is really useful. Otherwise you'd have variable references being passed around all over the place. And that can yield some really interesting bugs when a variable in one part of an application affects another variable in another part of the app. And not because it's passed, but because a reference was made somewhere along the line.

In general, I don't use variable references that much. It's rare that I find an honest need for them. But I do use object references all the time. I use them so much, that I'm happy that they are the default. Otherwise I'd need to write some operator (since & denotes a variable reference, there'd need to be another to denote an object reference). And considering that I rarely use clone, I'd say that 99.9% of use cases should use object references (so make the operator be used for the lower frequency cases)...

JMHO

I've also created a video explaining these differences. Check it out on YouTube.

橘和柠 2024-09-23 22:22:39

简而言之:

在 PHP 5+ 中,对象是通过引用传递的。在 PHP 4 中,它们是按值传递的(这就是为什么它有运行时按引用传递,但已被弃用)。因此,您必须使用 PHP5 中的clone 运算符来复制对象:

$objectB = clone $objectA;

另请注意,这只是通过引用传递的对象,而不是其他变量。以下内容可能会让您更清楚:

In Short:

In PHP 5+ objects are passed by reference. In PHP 4 they are passed by value (that's why it had runtime pass by reference, which became deprecated). So, you have to use the clone operator in PHP5 to copy objects:

$objectB = clone $objectA;

Also note that it's just objects that are passed by reference, not other variables. The following may clear you up more:

野鹿林 2024-09-23 22:22:39

我写了一个演示文稿来更好地解释 php 如何使用其变量管理内存:

https://docs.google.com/presentation/d/1HAIdvSqK0owrU-uUMjwMWSD80H-2IblTlacVcBs2b0k/pub?start=false&loop=false&delayms=3000

一看;)

i've written a presentation to explain better how php manage memory with its variables:

https://docs.google.com/presentation/d/1HAIdvSqK0owrU-uUMjwMWSD80H-2IblTlacVcBs2b0k/pub?start=false&loop=false&delayms=3000

take a look ;)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文