The problem is simple: I have an object like
{a:'A', b:'B'}
and i want it to be like
{a:'A', new_a:'A', b:'B', new_b:'B'}
The code used is:
<?php
$obj = new stdClass();
$obj->a = 'A';
$obj->b = 'B';
foreach($obj as $field=>$value)
{
$obj->{'new_'.$field} = $value;
}
The output is:
Fatal error: Allowed memory size of 134217728 bytes exhausted (tried to allocate 21290 bytes) in /path/to on line 9
Line 9 is this:
$obj->{'new_'.$field} = $value
I do have alternatives to solve the problem, but i don't understand why this particular code generates this error. Does anybody know the reason for this error, eventually an explanation. Thank you!
The problem is, as you're iterating the source object properties, you're adding more properties to the source object, so the foreach
loop can never end.
You can see this happening by adding a var_dump
call to the loop:
foreach ($obj as $field => $value)
{
$obj->{'new_'.$field} = $value;
var_dump($obj);
}
Results in:
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"]=>
...
Instead, create a new object and replace the old one:
$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;
}
Or even:
$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;
}
AS told you have to create another $obj
instead of using the object inside the loop
$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);
You are appending more data unto the same object you are Looping through, using also the properties of the same Object.... To counter that, you can just do something like this:
<?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);
UPDATE
If you wish to be consistent (ie: without Cloning) and also for reasons that @Dan has mentioned, You could simply use stdClass()
like so:
$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)
I'm not sure why there are so many suggestions to create a second object to work around this. In my opinion, the simplest thing to do would just be to grab the fields before the loop with get_object_vars
, so that you're only iterating over the initial fieldset:
$obj = new stdClass();
$obj->a = 'A';
$obj->b = 'B';
$fields = get_object_vars($obj);
foreach ($fields as $field => $value) {
$obj->{'new_'.$field} = $value;
}
your code is stuck in a infinite loop because if you have:
$obj = new stdClass();
$obj->a = 'A';
$obj->b = 'B';
foreach($obj as $field=>$value)
{
$obj->{'new_'.$field} = $value;
}
In each iteration, you add a new position into the object, and this position must be iterated by the foreach.
You can clone the original object and iterate the clone, into the iteration you can add the new position to the original object.
$obj = new stdClass();
$obj->a = 'A';
$obj->b = 'B';
$objcopy = clone $obj;
foreach($objcopy as $field=>$value)
{
$obj->{'new_'.$field} = $value;
}