Search code examples
phpzend-framework

safely get array element value for defined and undefined indexes


I'm getting tired of writing ternary expressions to sanitize the data, things like:

$x = isset($array['idx']) ? $array['idx'] : null;
// and
$x = !empty($array['idx']) ? $array['idx'] : null;

Is there a native way or ZF accessor/filter to get array element value for some given array without:

  • disabling error_reporting
  • ternary isset/empty check
  • error control operator @
  • creating my own global function or application accessor/filter

Something like:

$x = get_if_set($array['idx']);
// or 
$x = Zend_XXX($array, 'idx')

Solution

  • Since PHP 7.0

    Things are much more easy - thanks to Andrea Faulds and Nikita Popov for - the Null Coalescing Operator ??Docs, Migration, RFC:

    $x = $array['idx'] ?? NULL;
    

    or with a $default:

    $x = $array['idx'] ?? $default ?? NULL;
    

    Like isset or empty it gives no warning and the expression falls through to the right (if unset). if set and not NULL the value is taken. This is also how $default in the previous example works, always, even if undefined.


    Since PHP 7.4

    Thanks to Midori Kocak - is the Null Coalescing Assignment Operator ??=Docs, RFC (which was one of the things I missed after ??) allows to assign default values directly:

    $array['idx'] ??= null;
    $x = $array['idx'];
    

    I don't use it by far as often as ??, but it is good to know about it, especially if while break up data-handling logic and want to have defaults early.


    Original old answer


    As far as you only need NULL as "default" value, you can make use of the error suppression operator:

    $x = @$array['idx'];
    

    Criticism: Using the error suppression operator has some downsides. First it uses the error suppression operator, so you can not easily recover issues if that part of the code has some. Additionally the standard error situation if undefined does pollute looking for screams. Your code is not as expressing itself as precise as it could be. Another potential issue is to make use of an invalid index value, e.g. injecting objects for indexes etc.. This would get unnoticed.

    It will prevent warnings. However if you like to allow other default values as well, you can encapsulate the access to an array offset via the ArrayAccess interface:

    class PigArray implements ArrayAccess
    {
        private $array;
        private $default;
    
        public function __construct(array $array, $default = NULL)
        {
            $this->array   = $array;
            $this->default = $default;
        }
    
        public function offsetExists($offset)
        {
            return isset($this->array[$offset]);
        }
    
        public function offsetGet($offset)
        {
            return isset($this->array[$offset]) 
                ? $this->array[$offset] 
                : $this->default
                ;
        }
    
        public function offsetSet($offset, $value)
        {
            $this->array[$offset] = $value;
        }
    
        public function offsetUnset($offset)
        {
            unset($this->array[$offset]);
        }
    }
    

    Usage:

    $array = array_fill_keys(range('A', 'C'), 'value');
    $array = new PigArray($array, 'default');
    $a     = $array['A'];   # string(13) "value"
    $idx   = $array['IDX']; # NULL "default"
    
    var_dump($a, $idx);
    

    Demo: https://eval.in/80896