How to add property to object (SimpleXMLElement) using loop (reference) - php

I have code that retrieves list of data in Object $xmlContent
$source = 'http://www.bnm.org/en/official_exchange_rates?get_xml=1&date=23.11.2016';
$xmlString = file_get_contents($source);
$xmlContent = new \SimpleXMLElement($xmlString);
How can I add property by reference to the object like we can do this in case of Array?
foreach ($xmlContent as $k => &$v) {
$v['test_property'] = any_function($v->value);
}
This code will not work beacuse I can't change and add any values by reference to Object.
How can I add new items to object in this case?

You can use the addChild function for that:
$v; // $v is a SimpleXMLElement object
$v->addChild('nodeName', 'nodeContent');

foreach ($xmlContent as $k => $v) {
$v->addAttribute('test_property', any_function($v->value));
}

Related

json structure difference after edits

I have json string that I have to edit and then transform back to json. But unfortunately I can't really restore the json structure.
The structure of the original json string ($json):
"[{"Language":{"0":"EN"},"Text":{"0":"xxx"},"ContentType":{"0":"PlainText"}},
{"Language":{"0":"DE"},"Text":{"0":"xxx"},"ContentType":{"0":"PlainText"}},
{"Language":{"0":"FR"},"Text":{"0":"xxx"},"ContentType":{"0":"PlainText"}}]"
The structure I get after my edits ($newJson):
"{"0":{"Language":{"0":"EN"},"Text":{"0":"yyy"},"ContentType":{"0":"PlainText"}},
"1":{"Language":{"0":"DE"},"Text":{"0":"yyy"},"ContentType":{"0":"PlainText"}},
"2":{"Language":{"0":"FR"},"Text":{"0":"yyy"},"ContentType":{"0":"PlainText"}}}"
Here is what I do with my edits:
$jsonArray = object_to_array(json_decode($json));
$editedJsonArray = someLoopStuff($jsonArray);
$newJson = json_encode(array_to_object(($editedJsonArray)));
function object_to_array($obj) {
if(is_object($obj)) $obj = (array) $obj;
if(is_array($obj)) {
$new = array();
foreach($obj as $key => $val) {
$new[$key] = $this->object_to_array($val);
}
}
else $new = $obj;
return $new;
}
function array_to_object($a) {
if (is_array($a) ) {
foreach($a as $k => $v) {
$a[$k] = $this->array_to_object($v);
}
return (object) $a;
}
return $a;
}
Do you have an idea how I could get the same structure as the original json?
Use arrays instead of objects. Pass true to json_decode() as second argument and then do your stuff on arrays.
$jsonArray = json_decode($json, true);
Then just make your operation in loop on $jsonArray and simply use json_encode() without any additional work.
To achieve exactly same output as you have on input you need to cast subarrays on objects:
$jsonArray = json_decode('[{"Language":{"0":"EN"},"Text":{"0":"xxx"},"ContentType":{"0":"PlainText"}},{"Language":{"0":"DE"},"Text":{"0":"xxx"},"ContentType":{"0":"PlainText"}},{"Language":{"0":"FR"},"Text":{"0":"xxx"},"ContentType":{"0":"PlainText"}}]', true);
foreach ($jsonArray as &$item) {
foreach ($item as &$val) {
$val = (object) $val;
}
unset($val);
}
unset($item);
var_dump(json_encode($jsonArray));
Output:
string(226) "[{"Language":{"0":"EN"},"Text":{"0":"xxx"},"ContentType":{"0":"PlainText"}},{"Language":{"0":"DE"},"Text":{"0":"xxx"},"ContentType":{"0":"PlainText"}},{"Language":{"0":"FR"},"Text":{"0":"xxx"},"ContentType":{"0":"PlainText"}}]"
What if you would try to avoid using functions object_to_array and array_to_object. In the encoding part it is not necessary, because json_encode can handle objects or arrays. In the first part json_decode can be called with second optional parameter set to true to produce array instead of object. See PHP manual.

PHP: Set object properties inside a foreach loop

Is it possible to set property values of an object using a foreach loop?
I mean something equivalent to:
foreach($array as $key=>$value) {
$array[$key] = get_new_value();
}
EDIT: My example code did nothing, as #YonatanNir and #gandra404 pointed out, so I changed it a little bit so it reflects what I meant
You can loop on an array containing properties names and values to set.
For instance, an object which has properties "$var1", "$var2", and "$var3", you can set them this way :
$propertiesToSet = array("var1" => "test value 1",
"var2" => "test value 2",
"var3" => "test value 3");
$myObject = new MyClass();
foreach($propertiesToSet as $property => $value) {
// same as $myObject->var1 = "test value 1";
$myObject->$property = $value;
}
Would this example help at all?
$object = new stdClass;
$object->prop1 = 1;
$object->prop2 = 2;
foreach ($object as $prop=>$value) {
$object->$prop = $object->$prop +1;
}
print_r($object);
This should output:
stdClass Object
(
[prop1] => 2
[prop2] => 3
)
Also, you can do
$object = new stdClass;
$object->prop1 = 1;
$object->prop2 = 2;
foreach ($object as $prop=>&$value) {
$value = $value + 1;
}
print_r($object);
You can implement Iterator interface and loop through the array of objects:
foreach ($objects as $object) {
$object->your_property = get_new_value();
}
Hacked away at this for a few hours and this is what i finally used. Note the parameters passed by reference in two places. One when you enter the method and the other in the foreach loop.
private function encryptIdsFromData(&$data){
if($data == null)
return;
foreach($data as &$item){
if(isset($item["id"]))
$item["id"] = $this->encrypt($item["id"]);
if(is_array($item))
$this->encryptIdsFromData($item);
}
}

store objects in an array during foreach?

I am looking to store some objects in an array during a foreach loop. The problem is creating a unique object each time. I have to have some kind of index appending the name of each object. Here is what I have:
function table_rows($html) {
$dom = new Zend_Dom_Query($html);
$table_rows = $dom->query('tr');
$check_array = array();
foreach ($table_rows as $key=>$table_row) {
($check_object . $key) = new check_class;
($check_object . $key)->check_method1($table_row);
($check_object . $key)->check_method2($table_row);
($check_object . $key)->check_method3($table_row);
$check_array[] = (check_object . $key);
}
}
Am I even close?
You could use variables for that:
function table_rows($html) {
$dom = new Zend_Dom_Query($html);
$table_rows = $dom->query('tr');
$check_array = array();
foreach ($table_rows as $key=>$table_row) {
$object = new check_class;
$object->check_method1($table_row);
$object->check_method2($table_row);
$object->check_method3($table_row);
$check_array[] = $object;
}
}
Of course naming the variable for an object instance $object is not very descriptive, but I hope you get the idea.
This works because the first assignment in the for-loop overwrites the "old" instance, so $object unique for each iteration.
In case Jared Drake is right and what you mean is unique array keys, not object (variable) names.
$dom = new Zend_Dom_Query($html);
$table_rows = $dom->query('tr');
$check_array = array();
foreach ($table_rows as $key=>$table_row) {
$check_object = new check_class;
$check_object->check_method1($table_row);
$check_object->check_method2($table_row);
$check_object->check_method3($table_row);
$check_array['check_object' . $key] = $check_object;
}
}
Maybe I'm misunderstanding the question, but can't you just use the array_push method to add each object to the end of the array in your foreach loop?

Do foreach on a object in php

How do i perform foreach on a object . I wish to format the result that i get in my ci query
foreach ($CIResult as $key => $value) {
$CIResult -> $key = MyCustomFunction($value);
}
EDIT
I want CIResult to stay as a object only
foreach ($CIResult as $key => &$value) {
$value = MyCustomFunction($value);
}
It's important to note that this will only work on public properties of your object.
You can always cast an object to an array.
foreach ($CIResult as &$object) //by reference
{
$object->property = $new_value;
}
Is this what you want ?
foreach ($CIResult as $ciObj) {
// Access object properties like
$ciObj->property_name = format_name($ciObj->property_name);
}
Can you please, be more explicit on what you want to format ?
foreach((array)$CIResult as $key => $value)
$CIResult->$key = MyCustomFunction($value);

php simplexml - string as object

Hoping somebody can advise on an issue I have with simplexml.
I need to specify the paths for various nodes but I'm not sure if this is possible.
$xml = new SimpleXMLElement($xmlstr);
$image1 = 'images->image[0]->image';
foreach ($xml->record as $record) {
echo $record->$image1; // i need this be be recognised as $record->images->image[0]->image
}
Hope this makes sense! Thanks
You can use an array for this:
$xml = new SimpleXMLElement($xmlstr);
$levels = array('images', array('key' => 'image', 'index' => 0), 'image');
foreach ($xml->record as $record) {
$obj = $record;
foreach($levels as $level) {
if(is_array($level))
$obj = $obj->{$level['key']}[$level['index']];
else
$obj = $obj->$level;
}
echo $obj;
}
This builds up the hierarchy by reassigning $obj equal to itself -> whatever is next in the array.
PHP cannot interpolate array indices in strings, so if you need to use them, just use an associate array as shown above. :-)

Categories