PHP object 在 foreach 循环中加载为参考
PHP object loaded as reference in foreach loop
我正在遍历一个 object 并且我试图在更改其中一个变量的同时复制其中一个项目。
但是当我复制原来的然后在新的中更改标题时,旧的也随之改变。它不应该,因为我没有将它初始化为参考。
$calendar = array(
(object)[
'id' => 1,
'title' => 'original 1',
],
(object)[
'id' => 2,
'title' => 'original 2',
],
(object)[
'id' => 3,
'title' => 'original 3',
],
);
foreach ($calendar AS $key => $item){
if($item->id == 2){
$item->title = 'new 2';
array_splice($calendar, $key, 0, [1]);
$calendar[$key] = $item;
}
}
echo "<pre>";
print_r($calendar);
die();
我希望它的输出保持 original 2
不变。但它随之改变。
(
[0] => stdClass Object
(
[id] => 1
[title] => original 1
)
[1] => stdClass Object
(
[id] => 2
[title] => new 2
)
[2] => stdClass Object
(
[id] => 2
[title] => new 2
)
[3] => stdClass Object
(
[id] => 3
[title] => original 3
)
)
即使我制作了一个新的 object 并使用那个进行更改,它仍然会更改原始文件。
foreach ($calendar AS $key => $item){
if($item->id == 2){
$new_item = $item;
$new_item->title = 'new 2';
array_splice($calendar, $key, 0, [1]);
$calendar[$key] = $new_item;
}
}
现在我可能可以通过从头开始制作一个新的 object 并将值一个一个地复制到其中来解决这个问题。但这有什么乐趣呢?
所以我的问题是...为什么会这样?尽管我没有将 $item
转换为 &$item
很简单 PHP 对象赋值不会创建新对象。它只是创建一个指向同一对象的新指针。
我想你想使用 clone
关键字:
foreach ($calendar AS $key => $item){
if($item->id == 2){
$new_item = clone $item;
$new_item->title = 'new 2';
array_splice($calendar, $key, 0, [1]);
$calendar[$key] = $new_item;
}
}
分配还是克隆?
因为您正在使用对象,问题是 $new_item = $item;
没有创建新对象,它创建了 [=18= 的 新引用 ], 命名为 $new_item
.
在下面的例子中,$a
和$b
是同一个对象:
$a = new stdclass;
$b = $a;
var_dump($a, $b);
输出为:
object(stdClass)#1 (0) {...} // same object #1
object(stdClass)#1 (0) {...} // same object #1
克隆
您可以使用关键字 clone
创建一个新实例:
$a = new stdclass;
$b = clone $a; // Clone the object
var_dump($a, $b);
输出:
object(stdClass)#1 (0) {...} // object #1
object(stdClass)#2 (0) {...} // new object #2
因此,在您的情况下,您可以使用:
if ($item->id == 2) {
$clone = clone $item; // << Create a COPY of $item
$clone->title = 'new 2'; // Update the copy, not the reference
$calendar[$key] = $clone; // Add this copy to final array
// ...
}
关于参数的说明
当您使用对象作为某些函数的参数时,对象是 引用,因此,可以在该函数中更新给定对象。这是一个简单的例子(demo):
function updateObject(object $object): void {
$object->newProperty = true;
}
$obj = new stdClass;
var_dump($obj);
updateObject($obj);
var_dump($obj);
上面的代码给出了以下(精简)输出:
object(stdClass)#1 (0) { }
object(stdClass)#1 (1) { ["newProperty"]=> bool(true) }
进一步阅读:Objects and references
我正在遍历一个 object 并且我试图在更改其中一个变量的同时复制其中一个项目。
但是当我复制原来的然后在新的中更改标题时,旧的也随之改变。它不应该,因为我没有将它初始化为参考。
$calendar = array(
(object)[
'id' => 1,
'title' => 'original 1',
],
(object)[
'id' => 2,
'title' => 'original 2',
],
(object)[
'id' => 3,
'title' => 'original 3',
],
);
foreach ($calendar AS $key => $item){
if($item->id == 2){
$item->title = 'new 2';
array_splice($calendar, $key, 0, [1]);
$calendar[$key] = $item;
}
}
echo "<pre>";
print_r($calendar);
die();
我希望它的输出保持 original 2
不变。但它随之改变。
(
[0] => stdClass Object
(
[id] => 1
[title] => original 1
)
[1] => stdClass Object
(
[id] => 2
[title] => new 2
)
[2] => stdClass Object
(
[id] => 2
[title] => new 2
)
[3] => stdClass Object
(
[id] => 3
[title] => original 3
)
)
即使我制作了一个新的 object 并使用那个进行更改,它仍然会更改原始文件。
foreach ($calendar AS $key => $item){
if($item->id == 2){
$new_item = $item;
$new_item->title = 'new 2';
array_splice($calendar, $key, 0, [1]);
$calendar[$key] = $new_item;
}
}
现在我可能可以通过从头开始制作一个新的 object 并将值一个一个地复制到其中来解决这个问题。但这有什么乐趣呢?
所以我的问题是...为什么会这样?尽管我没有将 $item
转换为 &$item
很简单 PHP 对象赋值不会创建新对象。它只是创建一个指向同一对象的新指针。
我想你想使用 clone
关键字:
foreach ($calendar AS $key => $item){
if($item->id == 2){
$new_item = clone $item;
$new_item->title = 'new 2';
array_splice($calendar, $key, 0, [1]);
$calendar[$key] = $new_item;
}
}
分配还是克隆?
因为您正在使用对象,问题是 $new_item = $item;
没有创建新对象,它创建了 [=18= 的 新引用 ], 命名为 $new_item
.
在下面的例子中,$a
和$b
是同一个对象:
$a = new stdclass;
$b = $a;
var_dump($a, $b);
输出为:
object(stdClass)#1 (0) {...} // same object #1
object(stdClass)#1 (0) {...} // same object #1
克隆
您可以使用关键字 clone
创建一个新实例:
$a = new stdclass;
$b = clone $a; // Clone the object
var_dump($a, $b);
输出:
object(stdClass)#1 (0) {...} // object #1
object(stdClass)#2 (0) {...} // new object #2
因此,在您的情况下,您可以使用:
if ($item->id == 2) {
$clone = clone $item; // << Create a COPY of $item
$clone->title = 'new 2'; // Update the copy, not the reference
$calendar[$key] = $clone; // Add this copy to final array
// ...
}
关于参数的说明
当您使用对象作为某些函数的参数时,对象是 引用,因此,可以在该函数中更新给定对象。这是一个简单的例子(demo):
function updateObject(object $object): void {
$object->newProperty = true;
}
$obj = new stdClass;
var_dump($obj);
updateObject($obj);
var_dump($obj);
上面的代码给出了以下(精简)输出:
object(stdClass)#1 (0) { }
object(stdClass)#1 (1) { ["newProperty"]=> bool(true) }
进一步阅读:Objects and references