Mornor
Mornor

Reputation: 3803

Dynamically dig into JSON with PHP

Okay, so I need to dynamically dig into a JSON structure with PHP and I don't even know if it is possible.

So, let's say that my JSON is stored ad the variable $data:

$data = {
  'actions':{
     'bla': 'value_actionBla',
     'blo': 'value_actionBlo', 
  }
}

So, to access the value of value_actionsBla, I just do $data['actions']['bla']. Simple enough.

My JSON is dynamically generated, and the next time, it is like this:

$data = {
  'actions':{
     'bla': 'value_actionBla',
     'blo': 'value_actionBlo', 
     'bli':{
       'new': 'value_new'
     }
  }
}

Once again, to get the new_value, I do: $data['actions']['bli']['new'].

I guess you see the issue.

If I need to dig two levels, then I need to write $data['first_level']['second_level'], with three, it will be $data['first_level']['second_level']['third_level'] and so on ...

Is there any way to perform such actions dynamically? (given I know the keys)

EDIT_0: Here is an example of how I do it so far (in a not dynamic way, with 2 levels)

// For example, assert that 'value_actionsBla' == $data['actions']['bla']
foreach($data as $expected => $value) {
  $this->assertEquals($expected, $data[$value[0]][$value[1]]);
}

EDIT_1

I have made a recursive function to do it, based on the solution of @Matei Mihai:

private function _isValueWhereItSupposedToBe($supposedPlace, $value, $data){
        foreach ($supposedPlace as $index => $item) {
            if(($data = $data[$item]) == $value)
                return true;
            if(is_array($item))
                $this->_isValueWhereItSupposedToBe($item, $value, $data);
        }
        return false;
}

public function testValue(){
        $searched = 'Found';
        $data = array(
            'actions'  => array(
                'abort' => '/abort',
                'next' => '/next'
            ),
            'form' => array(
                'title' => 'Found'
            )
        );
        $this->assertTrue($this->_isValueWhereItSupposedToBe(array('form', 'title'), $searched, $data));
}

Upvotes: 1

Views: 236

Answers (2)

Tobias Xy
Tobias Xy

Reputation: 2069

You could use a function like this to traverse down an array recursively (given you know all the keys for the value you want to access!):

function array_get_nested_value($data, array $keys) {
    if (empty($keys)) {
        return $data;
    }
    $current = array_shift($keys);
    if (!is_array($data) || !isset($data[$current])) {
        // key does not exist or $data does not contain an array
        // you could also throw an exception here
        return null;
    }
    return array_get_nested_value($data[$current], $keys);
}

Use it like this:

$array = [
    'test1' => [
        'foo' => [
            'hello' => 123
        ]
    ],
    'test2' => 'bar'
];
array_get_nested_value($array, ['test1', 'foo', 'hello']); // will return 123

Upvotes: 1

Mihai Matei
Mihai Matei

Reputation: 24276

You can use a recursive function:

function array_search_by_key_recursive($needle, $haystack)
{
    foreach ($haystack as $key => $value) {
        if ($key === $needle) {
             return $value;
        }
        if (is_array($value) && ($result = array_search_by_key_recursive($needle, $value)) !== false) {
             return $result;
        }
    }

    return false;
}

$arr = ['test' => 'test', 'test1' => ['test2' => 'test2']];

var_dump(array_search_by_key_recursive('test2', $arr));

The result is string(5) "test2"

Upvotes: 2

Related Questions