3

If I have this array,

ini_set('display_errors', true);
error_reporting(E_ALL);

$arr = array(
  'id' => 1234,
  'name' => 'Jack',
  'email' => 'jack@example.com',
  'city' => array(
    'id' => 55,
    'name' => 'Los Angeles',
    'country' => array(
      'id' => 77,
      'name' => 'USA',
     ),
  ),
);

I can get the country name with

$name = $arr['city']['country']['name'];

But if the country array doesn't exist, PHP will generate warning:

Notice: Undefined index ... on line xxx

Sure I can do the test first:

if (isset($arr['city']['country']['name'])) {
  $name = $arr['city']['country']['name'];
} else {
  $name = '';  // or set to default value;
}

But that is inefficient. What is the best way to get $arr['city']['country']['name'] without generating PHP Notice if it doesn't exist?

flowfree
  • 16,356
  • 12
  • 52
  • 76
  • Why is it "inefficient"? – deceze May 28 '12 at 08:28
  • Where does the data come from? If from a third party, you should write one parse function to parse this into a standardized data structure of which you know which keys exist and which don't... – deceze May 28 '12 at 08:32
  • 1
    @deceze: It is inefficient since getting a single value takes 4+ lines. – flowfree May 28 '12 at 08:33

2 Answers2

5

I borrowed the code below from Kohana. It will return the element of multidimensional array or NULL (or any default value chosen) if the key doesn't exist.

function _arr($arr, $path, $default = NULL) 
{
  if (!is_array($arr))
    return $default;

  $cursor = $arr;
  $keys = explode('.', $path);

  foreach ($keys as $key) {
    if (isset($cursor[$key])) {
      $cursor = $cursor[$key];
    } else {
      return $default;
    }
  }

  return $cursor;
}

Given the input array above, access its elements with:

echo _arr($arr, 'id');                    // 1234
echo _arr($arr, 'city.country.name');     // USA
echo _arr($arr, 'city.name');             // Los Angeles
echo _arr($arr, 'city.zip', 'not set');   // not set
flowfree
  • 16,356
  • 12
  • 52
  • 76
3

The @ error control operator suppresses any errors generated by an expression, including invalid array keys.

$name = @$arr['city']['country']['name'];
Core Xii
  • 6,270
  • 4
  • 31
  • 42
  • 1
    Actually I want to write clean code, so I avoid `@` to catch any warnings and notices and fix them. – flowfree May 28 '12 at 09:14
  • 1
    If you wanted to write clean code, then you would use `isset()` as you explain in your very question. But it's verbose, which is why you're looking for alternatives. `@` is the least verbose of them. – Core Xii May 28 '12 at 09:41