Stop waiting, start array dereferencing in PHP now!

Ever since I started programming object oriented PHP I’ve been using function chaining and function dereferencing. But there is another thing I’d like to be able to do that was added to the PHP trunk over 8 months ago that still hasn’t made it to the current release. The function I’m referring to is array dereferencing. Array dereferencing allows you to do the following.

function fruit()
{
	return array('a' => 'apple', 'b' => 'banana');
}

echo fruit()['a'];
// echoes 'apple'

This roughly translates to using the following code in a current version of PHP.

function fruit()
{
	return array('a' => 'apple', 'b' => 'banana');
}

$fruits = fruit();
echo $fruits['a'];
// echoes 'apple'

In my opinion this is somewhat clumsy and you could end up with a lot of unnecessary lines of code because of all the added variables. On the other hand, array dereferencing has often been protested because of the risk of a memory leak but after a proper evaluation they decided to finally submit the patch to the trunk. Because I got tired of waiting for this to be included in PHP 5.4 or 6 I decided to write a little code snippit for this exact purpose.

function ad($array, $index)
{
	return $array[$index];
}

Now I can use the following code to emulate the use array dereferencing and spare all the extra code.

function fruit()
{
	return array('a' => 'apple', 'b' => 'banana');
}

echo ad(fruit(), 'b');
// echoes 'banana'
// This mimics the use of echo fruit()['b'];

This function prevents you from having to create temporary variables and could spare you several lines of code. And when array dereferencing is finaly implemented this function is easily replaced with the native one.

19 Replies to “Stop waiting, start array dereferencing in PHP now!”

  1. This is a feature that can be avoided by refactoring the function to output either a single value or a group of values. Or use the single value function to create the group of values function.

    function fruit($key)
    {
    	// code to fetch items based on parameter
    	return (count($fetched_items) == 1) ? $fetched_items[0] : $fetched_items;
    }
    
    function fruits()
    {
    	return fruit(array('a','b'));
    }
    

    The feature will lead to people using multivalue functions like they use an asterisk in sql select queries.

      1. The point of my comment is that it’s better to limit the data returned by the function than to add a feature/function to the programming language. This will cut the memory use, adds performance and makes the code more maintainable.

        function fruits($key='')
        {
        	$arr = (func_num_args() == 0) ? array('a','b') : func_get_args() ;
        	$fetched = array();
        	foreach($arr as $k)
        	{
        		switch($k)
        		{
        			case 'a' : $fetched['a'] = 'ananas'; break;
        			case 'b' : $fetched['b'] = 'banana'; break;
        		}
        	}
        	return (count($fetched) == 1) ? current($fetched) : $fetched ;
        }
        

        now you still can do

        foreach(fruits() as $fruit){ /* do something with $fruit */ }
        

        But now you can also do

        echo fruits('a');
        
  2. This isn’t yet in dry towels for 5.4. They still could do another afternoon IRC session and settle on the angle bracket syntax instead to evade parser woes:

    $a = fruits()<'a'>

    More seriously, your workaround function is quite neat. Especially the short name. Should become a standard snippet for everyone stuck on PHP < 5.2.

  3. Although I don’t like adding global functions, it’s a nice idea. David has also a good point on refactoring, at the end of the day it depends on the case and the right usage.

    I see array-deref more useful to access a specific key of an associative array, for instance:

    Zend_Loader_Autoloader_Resource::getResourceTypes()['model']['path']
    
  4. Is there an actual situation where it is worth passing around an array when you only want a single item?

    Remember that your array is returned by value – if you’ve got a sizable data structure in that array, you might be copying a lot of data to get almost nothing from it.

    class FruitStand {
    	private $fruits = array('a' => 'apple', 'b' => 'banana');
    	function fruit($letter) { 
    		return $this->fruits[$letter];
    	}
    }
    
    1. As far as I know PHP internally doesn’t actually copy a data structure until it is changed from its original. That’s the reason why foreach can still be efficient when it works on a “copy” of the array. I tested this myself with memory_get_usage and it seems to be true. So I guess this probably won’t be an issue.

  5. Sometimes you have to work with a third party library that you do not want to change for maintainability, so you get what you download.

    Array dereferencing is similar to using a function result as an object to get a property:

    // already possible in PHP
    $value = foo::bar1()->property;
    
    // array dereferencing
    $value = foo::bar2()['property'];
    
    1. This opens another workaround option actually:

      object(bar2::get_array())->property
      

      If you beforehand define a conversion function:

      function object($a) { return (object)$a; }
      
  6. Could also use a closure:

    function fruit()
    {
        return array('apple' => 'red', 'banana' => 'yellow');
    }
    
    $deref = function(Array $arr, $idx){ return $arr[$idx]; };
    $deref(fruit(), 'apple');
    

Comments are closed.