Okay, Lets say I have an object with properties like this:
$testObj->wind->windi // this returns a value like 100 mph
$testObj->wind->windii // this returns a value like 110 mph
I need to access a property but I don't know what property explicitly, Instead I have a string like this:
$str = 'wind->windii';
Calling predefined values works:
echo $testObj->wind->windii; //results in 110 mph
The Problem: I need a way to get the values without hard coding the actual properties:
echo $testObj->$str; //and have it result in 110 mph
I thought this was a variable variables situation but I had no luck getting that to work and after a few hours of frustration I'm asking for help
*edit:
I also need to mention that the object name changes as well so we can't hard code $testObj but rather be able to take any object and any string and get it's properties
Also, bracket notation isn't working, it results in "Undefined property: stdClass::$wind->elevation"
For those following at home, this is the var_dump of $testObj
object(stdClass)#299 (2) {
["snow"]=>
object(stdClass)#315 (3) {
["elevation"]=>
string(5) "365.4"
["results"]=>
string(1) "6"
["status"]=>
int(1)
}
["wind"]=>
object(stdClass)#314 (5) {
["elevation"]=>
string(5) "365.4"
["windi"]=>
string(7) "100 mph"
["windii"]=>
string(7) "110 mph"
["windiii"]=>
string(7) "115 mph"
["status"]=>
int(1)
}
}
you can change it to this :
$str1 = 'wind';
$str2 = 'windii';
echo $testObj->{$str1}->{$str2};
In PHP you can access properties dynamically such as:
`
class test {
public testvar;
}
$newtest = new test();
$property = "testvar"
$newtest->{"testvar"} //or $newtest->{$property};
`
Depending on what you are doing you can you a foreach loop to get the key value pair as well.
`
foreach($newtest as $key=>$val){
}
`
Finally I have working code.
With mental support from #NigelRen
Emotional support from #FunkFortyNiner
And most of the code from this question about arrays
Test Object:
$obj = json_decode('{"snow":{"elevation":"365.4","results":"6","status":1},"wind":{"elevation":"365.4","windi":"100 mph","windii":"110 mph","windiii":"115 mph","status":1}}');
Test Directory:
$path = 'wind:windii';
Getter:
function get($path, $obj) {
$path = explode(':', $path);
$temp =& $obj;
foreach($path as $key) {
$temp =& $temp->{$key};
}
return $temp;
}
var_dump(get($path, $obj)); //dump to see the result
Setter:
function set($path, &$obj, $value=null) {
$path = explode(':', $path);
$temp =& $obj;
foreach($path as $key) {
$temp =& $temp->{$key};
}
$temp = $value;
}
//Tested with:
set($path, $obj, '111');
Related
My goal is very simple, I want to parse the $GLOBALS variable in JSON (to log it). According to this Stackoverflow post, https://stackoverflow.com/a/23176085/1369579, I have to remove the recursive variable.
The following code works:
<?php
$global_array = $GLOBALS;
$index = array_search('GLOBALS',array_keys($global_array));
$json = json_encode(array_splice($global_array, $index, $index-1));
var_dump($json);
?>
It returns string(59) "{"GLOBALS":{"_GET":[],"_POST":[],"_COOKIE":[],"_FILES":[]}}" (in http://sandbox.onlinephpfunctions.com)
But I have to use an intermediate variable to store the array_splice result. When I do this, I doesn't works:
<?php
$global_array = $GLOBALS;
$index = array_search('GLOBALS',array_keys($global_array));
$splice_result = array_splice($global_array, $index, $index-1);
var_dump(json_encode($splice_result));
?>
The result is bool(false) and the json_last_error_msg() returns Recursion detected.
What the difference between the two versions? I really don't understand. For me foo(bar()) is the exactly the same code than $bar = bar(); foo($bar)…
I just understood my problem, the call of array_splice remove the $GLOBALS variable… but I still don't understand why.
I tried to put my code into a function, because I thought my problem was to put the code directly in the global scope:
<?php
function globalWithoutGlobals() {
$global_array = $GLOBALS;
$index = array_search('GLOBALS',array_keys($global_array));
array_splice($global_array, $index, 1);
return $global_array;
}
var_dump(json_encode(globalWithoutGlobals()));
var_dump(json_encode(globalWithoutGlobals()));
/* returns
# First call: success,
string(47) "{"_GET":[],"_POST":[],"_COOKIE":[],"_FILES":[]}"
# Second call : wtf ?!!
<br />
<b>Notice</b>: Undefined variable: GLOBALS in <b>[...][...]</b> on line <b>4</b><br />
*/
It's still very weird for me, the $global_array should be changed, not the $GLOBALS. To test this behaviour, I did the same thing on others arrays (with recursion too):
<?php
// Looks like $GLOBALS (with recursive element)
$globals_array = ["foo" => "bar"];
$globals_array['GLOBALS'] = &$globals_array;
$copy = $globals_array;
$index = array_search('GLOBALS', array_keys($copy));
array_splice($copy, $index, 1);
var_dump($globals_array);
var_dump($copy);
/* return:
array(2) {
["foo"]=>
string(3) "bar"
["GLOBALS"]=>
&array(2) {
["foo"]=>
string(3) "bar"
["GLOBALS"]=>
*RECURSION*
}
}
array(1) {
["foo"]=>
string(3) "bar"
}
*/
It returns the expected output, so why the behaviour is not the same with $GLOBALS ? 😩
To resolve my issue, I changed my approach and I stopped used array_splice, instead I just do a naive implementation with a foreach on the $GLOBALS and it works like expected:
<?php
function globalWithoutGlobals() {
$result = [];
foreach ($GLOBALS as $key => $value) {
if ($key !== 'GLOBALS') {
$result[$key] = $value;
}
}
return $result;
}
var_dump(json_encode(globalWithoutGlobals()));
var_dump(json_encode(globalWithoutGlobals()));
/* it returns:
string(47) "{"_GET":[],"_POST":[],"_COOKIE":[],"_FILES":[]}"
string(47) "{"_GET":[],"_POST":[],"_COOKIE":[],"_FILES":[]}"
*/
If someone know why the behaviour is different between my two first examples above. I'm curious to understand 😊
I have a following object:
object(Intro\IntroBundle\Entity\User)#333 (6) {
["id":"Intro\IntroBundle\Entity\User":private]=>
int(3)
["username":"Intro\IntroBundle\Entity\User":private]=>
string(3) "aaa"
["email":"Intro\IntroBundle\Entity\User":private]=>
string(9) "aa#aa.com"
["password":"Intro\IntroBundle\Entity\User":private]=>
string(4) "a1a1"
["age":"Intro\IntroBundle\Entity\User":private]=>
int(10)
["dateCreated":"Intro\IntroBundle\Entity\User":private]=>
object(DateTime)#330 (3) {
["date"]=>
string(26) "2011-01-01 01:01:00.000000"
["timezone_type"]=>
int(3)
["timezone"]=>
string(13) "Europe/Berlin"
}
}
I used methods:
array($entity);
json_decode(json_encode($entity), true);
get_object_vars ($entity);
and with a personal method
private function objToArray($obj){
$arr = array();
if(!is_object($obj) && !is_array($obj)){
$arr = $obj;
die("invalid data");
}
foreach ($obj as $key => $value)
{
if (!empty($value))
{
$arr[$key] = array();
objToArray($value, $arr[$key]);
}
else
{
$arr[$key] = $value;
}
}
return $arr;
}
All those methods return an empty array. Please tell me why? I mention that my object input ($entity) is not empty.
And also please don't give me dislike if you do not know the answer.
Your object's properties are private. If you var_dump() an object as you did it prints also private properties.
Have a look at this article http://php.net/manual/en/language.oop5.iterations.php. You can iterate object as you do but it iterates only public properties.
First of all, we can't see the scope. All your code is private (object properties and the method). Show the scope and we can help you better.
The problem seems to be here:
if (!empty($value))
{
$arr[$key] = array();
objToArray($value, $arr[$key]);
}
You are passing a second argument that doesn't defined in the method
private function objToArray($obj){...}
So you are passing a value to objToArray(), that value is a string I guess, and when it reach this line:
$arr = array();
if(!is_object($obj) && !is_array($obj)){
$arr = $obj;
die("invalid data");
}
Then it will display "invalid data", and empty your array.
As title, I did it like below:
$array=array(0,1,2,3);
$result=array();
function makeArray($array,$result,$value){
$str='$result';
for ($i=0;$i<count($array);$i++){
$str.='['.$i.']';
}
$str.='="'.$value.'";';
eval($str);
return $result;
}
It can realize result when param $result is an empty array,but It report an error when $result is an array.
Error like :
Cannot use a scalar value as an array.
Anyways can realize it?
Thanks first!
Use pass by reference, not eval:
function makeArray($indexes, &$result, $value) {
$here =& $result;
foreach ($indexes as $i) {
if (!(isset($here[$i]) && is_array($here[$i]))) {
$here[$i] = array();
}
$here =& $here[$i];
}
$here = $value;
}
$array=array(0,1,2,3);
$result=array();
makeArray($array, $result, 3);
var_dump($result);
Output:
array(1) {
[0]=>
array(1) {
[1]=>
array(1) {
[2]=>
array(1) {
[3]=>
int(3)
}
}
}
}
Putting & before a function parameter means it will be passed by reference, so modifications to the variable inside the function will affect the original variable that was passed. And using =& in an assignment assigns a reference, so the target variable is an alias for the source.
I'm looking for a sort of reversed func_get_args(). I would like to find out how the parameters were named when function was defined. The reason for this is I don't want to repeat myself when using setting variables passed as arguments through a method:
public function myFunction($paramJohn, $paramJoe, MyObject $paramMyObject)
{
$this->paramJohn = $paramJohn;
$this->paramJoe = $paramJoe;
$this->paramMyObject = $paramMyObject;
}
Ideally I could do something like:
foreach (func_get_params() as $param)
$this->${$param} = ${$param};
}
Is this an overkill, is it a plain stupid idea, or is there a much better way to make this happen?
You could use Reflection:
$ref = new ReflectionFunction('myFunction');
foreach( $ref->getParameters() as $param) {
echo $param->name;
}
Since you're using this in a class, you can use ReflectionMethod instead of ReflectionFunction:
$ref = new ReflectionMethod('ClassName', 'myFunction');
Here is a working example:
class ClassName {
public function myFunction($paramJohn, $paramJoe, $paramMyObject)
{
$ref = new ReflectionMethod($this, 'myFunction');
foreach( $ref->getParameters() as $param) {
$name = $param->name;
$this->$name = $$name;
}
}
}
$o = new ClassName;
$o->myFunction('John', 'Joe', new stdClass);
var_dump( $o);
Where the above var_dump() prints:
object(ClassName)#1 (3) {
["paramJohn"]=>
string(4) "John"
["paramJoe"]=>
string(3) "Joe"
["paramMyObject"]=>
object(stdClass)#2 (0) {
}
}
Code snippet that creates an array containing parameter names as keys and parameter values as corresponding values:
$ref = new ReflectionFunction(__FUNCTION__);
$functionParameters = [];
foreach($ref->getParameters() as $key => $currentParameter) {
$functionParameters[$currentParameter->getName()] = func_get_arg($key);
}
While it's not impossible to do it, it's usually better to use another method. Here is a link to a similar question on SO :
How to get a variable name as a string in PHP?
What you could do is pass all your parameters inside of an object, instead of passing them one by one. I'm assuming you are doing this in relation to databases, you might want to read about ORMs.
get_defined_vars will give you the parameter names and their values, so you can do
$params = get_defined_vars();
foreach ($params as $var=>$val) {
$this->${var} = $val;
}
This question already has answers here:
Convert a PHP object to an associative array
(33 answers)
Closed 6 months ago.
I'm using amazon product advertising api. Values are returned as a multidimensional objects.
It looks like this:
object(AmazonProduct_Result)#222 (5) {
["_code":protected]=>
int(200)
["_data":protected]=>
string(16538)
array(2) {
["IsValid"]=>
string(4) "True"
["Items"]=>
array(1) {
[0]=>
object(AmazonProduct_Item)#19 (1) {
["_values":protected]=>
array(11) {
["ASIN"]=>
string(10) "B005HNF01O"
["ParentASIN"]=>
string(10) "B008RKEIZ8"
["DetailPageURL"]=>
string(120) "http://www.amazon.com/Case-Logic-TBC-302-FFP-Compact/dp/B005HNF01O?SubscriptionId=AKIAJNFRQCIJLTY6LDTA&tag=*********-20"
["ItemLinks"]=>
array(7) {
[0]=>
object(AmazonProduct_ItemLink)#18 (1) {
["_values":protected]=>
array(2) {
["Description"]=>
string(17) "Technical Details"
["URL"]=>
string(217) "http://www.amazon.com/Case-Logic-TBC-302-FFP-Compact/dp/tech-data/B005HNF01O%3FSubscriptionId%3DAKIAJNFRQCIJLTY6LDTA%26tag%*******-20%26linkCode%3Dxm2%26camp%3D2025%26creative%3D386001%26creativeASIN%3DB005HNF01O"
}
}
[1]=>
object(AmazonProduct_ItemLink)#17 (1) {
["_values":protected]=>
array(2) {
I mean it also has array inside objects. I would like to convert all of them into a multidimensional array.
I know this is old but you could try the following piece of code:
$array = json_decode(json_encode($object), true);
where $object is the response of the API.
You can use recursive function like below:
function object_to_array($obj, &$arr)
{
if (!is_object($obj) && !is_array($obj))
{
$arr = $obj;
return $arr;
}
foreach ($obj as $key => $value)
{
if (!empty($value))
{
$arr[$key] = array();
objToArray($value, $arr[$key]);
}
else {$arr[$key] = $value;}
}
return $arr;
}
function convertObjectToArray($data) {
if (is_object($data)) {
$data = get_object_vars($data);
}
if (is_array($data)) {
return array_map(__FUNCTION__, $data);
}
return $data;
}
Credit to Kevin Op den Kamp.
I wrote a function that does the job, and also converts all json strings to arrays too. This works pretty fine for me.
function is_json($string) {
// php 5.3 or newer needed;
json_decode($string);
return (json_last_error() == JSON_ERROR_NONE);
}
function objectToArray($objectOrArray) {
// if is_json -> decode :
if (is_string($objectOrArray) && is_json($objectOrArray)) $objectOrArray = json_decode($objectOrArray);
// if object -> convert to array :
if (is_object($objectOrArray)) $objectOrArray = (array) $objectOrArray;
// if not array -> just return it (probably string or number) :
if (!is_array($objectOrArray)) return $objectOrArray;
// if empty array -> return [] :
if (count($objectOrArray) == 0) return [];
// repeat tasks for each item :
$output = [];
foreach ($objectOrArray as $key => $o_a) {
$output[$key] = objectToArray($o_a);
}
return $output;
}
This is an old question, but I recently ran into this and came up with my own solution.
array_walk_recursive($array, function(&$item){
if(is_object($item)) $item = (array)$item;
});
Now if $array is an object itself you can just cast it to an array before putting it in array_walk_recursive:
$array = (array)$object;
array_walk_recursive($array, function(&$item){
if(is_object($item)) $item = (array)$item;
});
And the mini-example:
array_walk_recursive($array,function(&$item){if(is_object($item))$item=(array)$item;});
In my case I had an array of stdClass objects from a 3rd party source that had a field/property whose value I needed to use as a reference to find its containing stdClass so I could access other data in that element. Basically comparing nested keys in 2 data sets.
I have to do this many times, so I didn't want to foreach over it for each item I need to find. The solution to that issue is usually array_column, but that doesn't work on objects. So I did the above first.
Just in case you came here as I did and didn't find the right answer for your situation, this modified version of one of the previous answers is what ended up working for me:
protected function objToArray($obj)
{
// Not an object or array
if (!is_object($obj) && !is_array($obj)) {
return $obj;
}
// Parse array
foreach ($obj as $key => $value) {
$arr[$key] = $this->objToArray($value);
}
// Return parsed array
return $arr;
}
The original value is a JSON string. The method call looks like this:
$array = $this->objToArray(json_decode($json, true));