stdClass动态成员 - 内存耗尽

时间:2018-01-18 15:54:16

标签: php

问题很简单: 我有一个像

这样的对象
{a:'A', b:'B'}

我希望它像

{a:'A', new_a:'A', b:'B', new_b:'B'}

使用的代码是:

<?php

$obj = new stdClass();
$obj->a = 'A';
$obj->b = 'B';

foreach($obj as $field=>$value)
{
    $obj->{'new_'.$field} = $value;
}

输出结果为:

Fatal error: Allowed memory size of 134217728 bytes exhausted (tried to allocate 21290 bytes) in /path/to on line 9

第9行是这样的:

$obj->{'new_'.$field} = $value

我确实有其他方法可以解决问题,但我不明白为什么这个特定的代码会产生这个错误。 有没有人知道这个错误的原因,最终解释。 谢谢!

5 个答案:

答案 0 :(得分:2)

问题是,当您迭代源对象属性时,您将向源对象添加更多属性,因此foreach循环永远不会结束。

您可以通过向循环添加var_dump调用来发现这种情况:

foreach ($obj as $field => $value)
{
    $obj->{'new_'.$field} = $value;
    var_dump($obj);
}

结果:

object(stdClass)#1 (29) {
  ["a"]=>
  string(1) "A"
  ["b"]=>
  string(1) "B"
  ["new_a"]=>
  string(1) "A"
  ["new_b"]=>
  string(1) "B"
  ["new_new_a"]=>
  string(1) "A"
  ["new_new_b"]=>
  string(1) "B"
  ["new_new_new_a"]=>
  ...

相反,创建一个新对象并替换旧对象:

$obj = new stdClass();
$obj->a = 'A';
$obj->b = 'B';

$newObj = new stdClass();

// Copy old properties
foreach ($obj as $field => $value) {
    $newObj->{$field} = $value;
}

// Create new properties
foreach($obj as $field => $value) {
    $newObj->{'new_' . $field} = $value;
}

甚至:

$obj = new stdClass();
$obj->a = 'A';
$obj->b = 'B';

$newObj = new stdClass();

// Copy old properties and create new
foreach ($obj as $field => $value) {
    $newObj->{$field} = $value;
    $newObj->{'new_' . $field} = $value;
}

答案 1 :(得分:2)

我不确定为什么有这么多建议来创建第二个对象来解决这个问题。在我看来,最简单的方法就是在使用get_object_vars 循环之前抓取字段,这样你只能迭代初始字段集:

$obj = new stdClass();
$obj->a = 'A';
$obj->b = 'B';

$fields = get_object_vars($obj);

foreach ($fields as $field => $value) {
    $obj->{'new_'.$field} = $value;
}

请参阅https://eval.in/937616

答案 2 :(得分:1)

您正在使用相同对象的属性将更多数据附加到您正在循环的同一对象....要解决这个问题,您可以执行以下操作:

<?php
$obj = new stdClass();
$obj->a = 'A';
$obj->b = 'B';
$obj2   = clone $obj;

foreach($obj as $field=>$value)
{
    $key    = 'new_'.$field;
    $obj2->{$key} = $value;
}
// IF YOU STILL WISH TO HAVE $obj AS YOUR MAIN OBJECT,
// YOU CAN AS WELL RE-CLONE $obj2 INTO $obj AND DELETE $obj2 LIKE SO:
$obj        = $obj2;
unset($obj2);

var_dump($obj);
var_dump($obj2);

enter image description here

<强>更新
如果你希望保持一致(即:没有克隆),并且出于@Dan提到的原因,你可以像这样简单地使用stdClass()

$obj    = new stdClass();
$obj->a = 'A';
$obj->b = 'B';
$obj2   = new stdClass();

foreach($obj as $field=>$value)
{
    $key    = 'new_'.$field;
    $obj2->{$field} = $value;
    $obj2->{$key}   = $value;
}
$obj        = clone $obj2;
unset($obj2);

var_dump($obj); 
// YIELDS: 
object(stdClass)[3]
  public 'a'        => string 'A' (length=1)
  public 'new_a'    => string 'A' (length=1)
  public 'b'        => string 'B' (length=1)
  public 'new_b'    => string 'B' (length=1)

答案 3 :(得分:0)

AS告诉你必须创建另一个$ obj
而不是在循环中使用对象

$obj = new stdClass();
$obj->a = 'A';
$obj->b = 'B';

$obj2 = new stdClass();
foreach($obj as $field=>$value)
{
    $obj2->{$field} = $value;
    $obj2->{'new_'.$field} = $value;
}
$obj = $obj2;
echo '<pre>';
var_dump($obj);

答案 4 :(得分:0)

你的代码陷入无限循环,因为如果你有:

$obj = new stdClass();
$obj->a = 'A';
$obj->b = 'B';

foreach($obj as $field=>$value)
{
    $obj->{'new_'.$field} = $value;
}

在每次迭代中,您都会在对象中添加一个新位置,并且该位置必须由foreach迭代。

您可以克隆原始对象并迭代克隆,进入迭代,您可以将新位置添加到原始对象。

$obj = new stdClass();
$obj->a = 'A';
$obj->b = 'B';
$objcopy = clone $obj;

foreach($objcopy as $field=>$value)
{
    $obj->{'new_'.$field} = $value;
}