PHP 7 将对象推送到数组后覆盖对象会导致覆盖该数组中的所有对象

PHP 7 overwriting an object after pushing it to array results in overwriting of all objects in that array

祝大家愉快。我是 PHP 的新手,在这里我试图将多个对象 ($viewership_prj) 推送到单个数组 ($viewership_prj_arr).

第一次写下面的。结果数组不正确。

基本上,每当将新对象推入数组时,该数组中的所有现有对象都会覆盖新推入对象的属性。

                         $viewership_prj_arr = array();
                         $viewership_prj = (object) array();
                         foreach($projects as $prj)
                         {   
                            /*...*/
                                            
                            $viewership_prj->title = $prj['project_title'];
                            $viewership_prj_arr[] = $viewership_prj;

                            // $viewership_prj_arr[] is [title1] after first loop
                            // [title2, title2] after second loop
                            // [title3, title3, title3] after third loop
                            // ...
                         }

然后我改成了这个,它起作用了。我在每个循环中声明了一个新对象。

                         $viewership_prj_arr = array();
                         foreach($projects as $prj)
                         {   
                            /*...*/

                            $viewership_prj = (object) array();
                                            
                            $viewership_prj->title = $prj['project_title'];
                            $viewership_prj_arr[] = $viewership_prj;

                            // $viewership_prj_arr[] is [title1] after first loop
                            // [title1, title2] after second loop
                            // [title1, title2, title3] after third loop
                            // ...
                         }

我很困惑。

我能想到的唯一原因是,当对象被压入数组时,它是通过引用传递的,而不是通过值传递的。我尝试查找手册 https://www.php.net/manual/en/language.oop5.references.php#:~:text=Objects%20and%20references%20%C2%B6,passed%20by%20references%20by%20default%22.&text=A%20PHP%20reference%20is%20an,the%20object%20itself%20as%20value。但对我来说意义不大。

有人可以帮我澄清一下吗?非常感谢。

过于简单化,PHP 将对象存储为

"identifier to object" => actual object

创建新对象$object_1 = (object)[] 存储

"identifier to object 1" => actual object 1

$object_1 = "identifier to object 1"

$object_1 的值是对对象 1 的引用不是实际对象 本身。它们是两个独立的项目,由标识符链接。

所以,当你这样做时

$object_1->title = "a";

$array[1] = $object_1;
$array[2] = $object_1;
$array[3] = $object_1;

在引擎盖下,它看起来像:

"identifier to object 1" => actual object 1->title = "a"

$array[
  1 => "identifier to object 1",   // (actual object 1->title = "a")
  2 => "identifier to object 1",   // (actual object 1->title = "a")
  3 => "identifier to object 1",   // (actual object 1->title = "a")
  ];

改变$object_1->title = "b"

  "identifier to object 1" => actual object 1->title = "b"

但不更改 $array 中的标识符。它们仍然是 “对象 1 的标识符”,因此 所有 数组的元素现在是:

$array[
  [1] => "identifier to object 1",   // (actual object 1->title = "b")
  [2] => "identifier to object 1",   // (actual object 1->title = "b")
  [3] => "identifier to object 1",   // (actual object 1->title = "b")
  ];

另外 $object_2 = $object_1 只会将 “标识符复制到对象 1”。两个变量都指向同一个对象:

$object_1 = "identifier to object 1"
$object_2 = "identifier to object 1"

任何包含对实际对象 1 的引用的变量 都可以更改 实际对象 1.

$object_1->title = "c";
 or
$object_2->title = "c";
 or
$array[3]->title = "c";

完全相同,因为它们都包含对同一个实际对象 1 的引用。所以改变一个就是改变所有。

如果您希望所有数组元素都有自己的对象,则必须为每个元素创建一个新对象,或者 - 如果您想使用前一个对象的值 - 使用 clone.

$array = [];
$names = [ "John", "Jack", "Jill" ];
$object = (object)[];
$object->name = "";
$object->coffee = "black with sugar";

foreach( $names as $name ){
  $object->name = $val;      //change the name of the actual object
  $array[] = clone $object;  //create a new object with the current values of $object
  }

会输出

$array[
 stdClass Object ( name=> John, coffee=> black with sugar ), 
 stdClass Object ( name=> Jack, coffee=> black with sugar ), 
 stdClass Object ( name=> Jill, coffee=> black with sugar ) 
]
//$object only contains the last change!
$object = stdClass Object ( name=> Jill, coffee=> black with sugar )