php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #79377 Property is not cloned with clone
Submitted: 2020-03-13 00:57 UTC Modified: 2020-03-13 02:42 UTC
From: mvorisek at mvorisek dot cz Assigned:
Status: Not a bug Package: Scripting Engine problem
PHP Version: 7.4.3 OS: Any
Private report: No CVE-ID: None
View Add Comment Developer Edit
Welcome! If you don't have a Git account, you can't do anything here.
You can add a comment by following this link or if you reported this bug, you can edit this bug over here.
(description)
Block user comment
Status: Assign to:
Package:
Bug Type:
Summary:
From: mvorisek at mvorisek dot cz
New email:
PHP Version: OS:

 

 [2020-03-13 00:57 UTC] mvorisek at mvorisek dot cz
Description:
------------
Seems like a core bug presented in all PHP versions (5.4.0 - 7.4.3 tested).

Please verify and fix asap.

Test script:
---------------
class A {
    public $elements = [];
    
    public function __construct()
    {
        $this->fields = &$this->elements; // this causes the issue
    }

    public function __clone()
    {
        // $elems = $this->elements; unset($this->elements); $this->elements = $elems; $this->fields = &$this->elements; // this is an immediate fix before fixed in PHP directly
    }
}

$x = new A();
$y = clone $x;
$y->elements['hello'] = 'world';

print_r($x);
print_r($y);

Expected result:
----------------
A Object
(
    [elements] => Array
        (
        )

    [fields] => Array
        (
        )

)
A Object
(
    [elements] => Array
        (
            [hello] => world
        )

    [fields] => Array
        (
            [hello] => world
        )

)

Actual result:
--------------
A Object
(
    [elements] => Array
        (
            [hello] => world
        )

    [fields] => Array
        (
            [hello] => world
        )

)
A Object
(
    [elements] => Array
        (
            [hello] => world
        )

    [fields] => Array
        (
            [hello] => world
        )

)

Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2020-03-13 00:59 UTC] requinix@php.net
-Status: Open +Status: Not a bug
 [2020-03-13 00:59 UTC] requinix@php.net
You made the property a reference. PHP quite happily cloned the reference.
 [2020-03-13 01:38 UTC] requinix@php.net
Regarding the code from your email, https://3v4l.org/Q557K

References are not pointers.

> $test = &$x->elements;
$test will not "point" to $x->elements. It will not be a reference "to" that property. Rather, this reference assignment will make it so that both of those symbols use the same data that is being stored internally by the engine. They are *both* references. Then when PHP clones the object, the property will be copied - including the fact that it is a reference (thus resulting in a *third* reference).

See https://www.php.net/manual/en/language.references.php


As a rule of thumb, whatever the problem may be, using references is *not* the solution.
 [2020-03-13 01:52 UTC] mvorisek at mvorisek dot cz
Is the statement about cloning documented and desired?

Outside cloning this approach makes sense and can not be even noticed, but shouln't clone create a (lazy - standard copy-on-write) copy of each scalar/array property no matter if this property was referenced or not?
 [2020-03-13 02:42 UTC] requinix@php.net
Here's a more in-depth explanation of references and PHP's variable/memory management:
http://www.phpinternalsbook.com/php5/zvals/memory_management.html

> Outside cloning this approach makes sense and can not be even noticed, but shouln't clone create a (lazy -
> standard copy-on-write) copy of each scalar/array property no matter if this property was referenced or not?
That's debatable. Copying the reference makes sense because the property itself is a reference, and not copying the reference makes sense because cloning is shallow. Could go either way.

But the current stance is that cloning preserves references.
> When an object is cloned, PHP will perform a shallow copy of all of the object's properties. Any properties
> that are references to other variables will remain references.
https://www.php.net/manual/en/language.oop5.cloning.php
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Sun May 19 03:01:33 2024 UTC