对象分配正在 PHP 中创建引用
Object assignment is creating a reference in PHP
我在将现有对象分配给数组时出现奇怪的行为。
在下面的示例中,我有一个包含一个 属性 的 class。我创建了一个包含 3 个实例的第一个数组(我们称它们为 2-4-6),然后使用第一个数组的一个对象(实例 4)创建了一个包含 2 个其他实例的第二个数组。在修改第二个数组中对象的值以创建 2 个新实例(即实例 3-5)时,实例 4 也被修改。因此,在第一个数组查询中,我得到了正确的值 (2-4-6),但在创建第二个数组后,我得到了修改后的值 (2-5-6)。我希望赋值运算符复制了对象,但它创建了对实例的引用。在示例中,我可以通过显式调用克隆来解决这个问题,但在更大范围内,这是行不通的(错误的代码优化?)。关于如何避免此问题的任何线索(或良好做法)?
谢谢!
<?php
class TestBase
{
private int $m_test = 0;
public function SetTest(int $v)
{
$this->m_test = $v;
}
public function GetTest() : int
{
return $this->m_test;
}
}
function getNewList(TestBase $ref) : array
{
$newlist = [3 => new TestBase(), 5 => $ref];
$newlist[3]->SetTest(3);
$newlist[5]->SetTest(5);
return $newlist;
}
$listOfTest = [2 => new TestBase(), 4 => new TestBase(), 6 => new TestBase()];
$listOfTest[2]->SetTest(2);
$listOfTest[4]->SetTest(4);
$listOfTest[6]->SetTest(6);
foreach ($listOfTest as $test)
{
echo $test->GetTest().'<br>';
}
// 2
// 4
// 6
//$ref = clone $listOfTest[4];
$ref = $listOfTest[4];
$newList = getNewList($ref);
foreach ($listOfTest as $test)
{
echo $test->GetTest().'<br>';
}
// 2
// 5
// 6
?>
问题在于 PHP 使用数组的方式。引用数组赋值
仅当参数和左值都是对数组的引用时才有效。如果传入一个对象,它将被复制并在两个地方设置对它的引用。后续对左值的重新赋值不会对原数组产生任何影响。
引用现有数组然后使用 clone
复制它可以解决这个问题。下面的示例显示了如何完成此操作,但您也可以使用工厂或其他方式创建一个新数组,该数组引用所有现有元素(通过对每个元素调用 get_object_vars()
)。
<?php
function getNewList(TestBase $ref) : array
{
$newlist = [3 => clone $ref, 5 => clone $ref];
$newlist[3]->SetTest(3);
$newlist[5]->SetTest(5);
return $newlist;
}
//$ref = clone $listOfTest[4];
$ref = &$listOfTest[4];
var_dump($ref); // TestBase Object (1) (2) { ["m_test"]=> int(5) }
//$newList = getNewList($ref);
foreach ($listOfTest as &$test)
{
echo "before: ".$test->GetTest().'<br>'; // 2, 4, 6 in output here!
var_dump($test); // TestBase Object (1) (2) { ["m_test"]=> int(4) }
echo "after: ".$test->GetTest().'<br>'; // 2, 4, 6 in output here!
var_dump($test); // TestBase Object (1) (2) { ["m_test"]=> int(4) }
}
?>
我在将现有对象分配给数组时出现奇怪的行为。 在下面的示例中,我有一个包含一个 属性 的 class。我创建了一个包含 3 个实例的第一个数组(我们称它们为 2-4-6),然后使用第一个数组的一个对象(实例 4)创建了一个包含 2 个其他实例的第二个数组。在修改第二个数组中对象的值以创建 2 个新实例(即实例 3-5)时,实例 4 也被修改。因此,在第一个数组查询中,我得到了正确的值 (2-4-6),但在创建第二个数组后,我得到了修改后的值 (2-5-6)。我希望赋值运算符复制了对象,但它创建了对实例的引用。在示例中,我可以通过显式调用克隆来解决这个问题,但在更大范围内,这是行不通的(错误的代码优化?)。关于如何避免此问题的任何线索(或良好做法)? 谢谢!
<?php
class TestBase
{
private int $m_test = 0;
public function SetTest(int $v)
{
$this->m_test = $v;
}
public function GetTest() : int
{
return $this->m_test;
}
}
function getNewList(TestBase $ref) : array
{
$newlist = [3 => new TestBase(), 5 => $ref];
$newlist[3]->SetTest(3);
$newlist[5]->SetTest(5);
return $newlist;
}
$listOfTest = [2 => new TestBase(), 4 => new TestBase(), 6 => new TestBase()];
$listOfTest[2]->SetTest(2);
$listOfTest[4]->SetTest(4);
$listOfTest[6]->SetTest(6);
foreach ($listOfTest as $test)
{
echo $test->GetTest().'<br>';
}
// 2
// 4
// 6
//$ref = clone $listOfTest[4];
$ref = $listOfTest[4];
$newList = getNewList($ref);
foreach ($listOfTest as $test)
{
echo $test->GetTest().'<br>';
}
// 2
// 5
// 6
?>
问题在于 PHP 使用数组的方式。引用数组赋值 仅当参数和左值都是对数组的引用时才有效。如果传入一个对象,它将被复制并在两个地方设置对它的引用。后续对左值的重新赋值不会对原数组产生任何影响。
引用现有数组然后使用 clone
复制它可以解决这个问题。下面的示例显示了如何完成此操作,但您也可以使用工厂或其他方式创建一个新数组,该数组引用所有现有元素(通过对每个元素调用 get_object_vars()
)。
<?php
function getNewList(TestBase $ref) : array
{
$newlist = [3 => clone $ref, 5 => clone $ref];
$newlist[3]->SetTest(3);
$newlist[5]->SetTest(5);
return $newlist;
}
//$ref = clone $listOfTest[4];
$ref = &$listOfTest[4];
var_dump($ref); // TestBase Object (1) (2) { ["m_test"]=> int(5) }
//$newList = getNewList($ref);
foreach ($listOfTest as &$test)
{
echo "before: ".$test->GetTest().'<br>'; // 2, 4, 6 in output here!
var_dump($test); // TestBase Object (1) (2) { ["m_test"]=> int(4) }
echo "after: ".$test->GetTest().'<br>'; // 2, 4, 6 in output here!
var_dump($test); // TestBase Object (1) (2) { ["m_test"]=> int(4) }
}
?>