34

Background

In every other programming language I use on a regular basis, it is simple to operate on the return value of a function without declaring a new variable to hold the function result.

In PHP, however, this does not appear to be so simple:

example1 (function result is an array)

<?php 
function foobar(){
    return preg_split('/\s+/', 'zero one two three four five');
}

// can php say "zero"?

/// print( foobar()[0] ); /// <-- nope
/// print( &foobar()[0] );     /// <-- nope
/// print( &foobar()->[0] );     /// <-- nope
/// print( "${foobar()}[0]" );    /// <-- nope
?>

example2 (function result is an object)

<?php    
function zoobar(){
  // NOTE: casting (object) Array() has other problems in PHP
  // see e.g., http://stackoverflow.com/questions/1869812
  $vout   = (object) Array('0'=>'zero','fname'=>'homer','lname'=>'simpson',);
  return $vout;
}

//  can php say "zero"?       
//  print zoobar()->0;         //  <- nope (parse error)      
//  print zoobar()->{0};       //  <- nope                    
//  print zoobar()->{'0'};     //  <- nope                    
//  $vtemp = zoobar();         //  does using a variable help?
//  print $vtemp->{0};         //  <- nope     
dreftymac
  • 27,818
  • 25
  • 108
  • 169
  • 15
    For the benefit of readers who don't scroll to the later answers, array derefencing has been added to PHP 5.4 (in beta at time of this comment)... – Michael Berkowski Dec 13 '11 at 21:59
  • 2
    **NOTE:** This question was incorrectly marked as a duplicate of [array dereferencing](http://stackoverflow.com/questions/13109). **This question is not a duplicate**, because it is not exclusively about arrays. A PHP function can return any value type, not just arrays (see example2 in the original post, where the function result is an object, and not an array). – dreftymac Apr 14 '15 at 15:33
  • For those who can't bother reading through all the answers, the most "beautiful" solution is [`call_user_func(function($a, $b){return $a[$b];}, $arr, $offset)`](http://stackoverflow.com/a/5022984/632951). The runner-up prize goes to [`current(array_slice($arr, $offset, 1))`](http://stackoverflow.com/a/5196607/632951). – Pacerier Jul 20 '15 at 19:48
  • @Pacerier by what metric are you declaring one more "beautiful" than the other? Is one more efficient? Frankly, the second choice is quicker and easier to write. – KyleFarris Jul 21 '15 at 20:31

22 Answers22

26

PHP can not access array results from a function. Some people call this an issue, some just accept this as how the language is designed. So PHP makes you create unessential variables just to extract the data you need.

So you need to do.

$var = foobar();
print($var[0]);
Ólafur Waage
  • 64,767
  • 17
  • 135
  • 193
  • 1
    I realise that I'm still incredibly new to this, but why is this a problem? It...makes sense to me that you'd need to create a variable to hold a value/result; though admittedly: *very new* – David says reinstate Monica Apr 13 '09 at 01:16
  • Some people call this an issue, but this is just how the language is designed. Other languages are designed in a way where this is possible, and people coming from those languages feel that this is an issue. – Ólafur Waage Apr 13 '09 at 01:17
  • I honestly don't know why this is the case but it is. – cletus Apr 13 '09 at 01:18
  • Thanks for the clarity @ Ólafur =) – David says reinstate Monica Apr 13 '09 at 01:22
  • 1
    It's an issue because it becomes very easy to lose track of where you are if you have a function that returns a structured variable or object. For example, what if you have $data['tvshow']['episodes'][1]['description'] as a valid address in your variable? – dreftymac Apr 13 '09 at 01:26
  • @ricebowl: no, it doesn't make sense. It would make sens to have for example $gdver = gd_info()["GD Version"]. The problem is, that PHP is not object oriented. – vartec Apr 13 '09 at 07:23
  • @Ólafur: actually I don't think there is other language which would have similar "feature". AFAIR, even in plain C you can dereference function result. +1 anyway, because that's the only correct answer. – vartec Apr 13 '09 at 07:31
  • @vartec, what array dereferencing has to do with OOP? – Ionuț G. Stan Apr 13 '09 at 11:41
  • 1
    Really, the language seems consistent on allowing fluent usage of results, so why not with arrays? Seems like they agreed. –  Dec 03 '12 at 17:33
  • 2
    @ÓlafurWaage, No, PHP is **not designed** this way. This is an oversight and not "just how the language is designed". It is precisely because this is an issue that it is **fixed** in PHP 5.4. – Pacerier Jul 20 '15 at 18:14
20

This is specifically array dereferencing, which is currently unsupported in php5.3 but should be possible in the next release, 5.4. Object dereferencing is on the other hand possible in current php releases. I'm also looking forward to this functionality!

Lightness Races in Orbit
  • 358,771
  • 68
  • 593
  • 989
smassey
  • 5,479
  • 20
  • 34
  • 1
    NOTE: This question was incorrectly marked as a duplicate of array dereferencing. This question is not a duplicate, because it is not exclusively about arrays. A PHP function can return any value type, not just arrays (see example2 in the original post, where the function result is an object, and not an array). – dreftymac May 13 '15 at 16:40
  • 2
    @dreftymac In PHP 7 this was cleaned up finally and you can now use a function call in any expression. – Andrea Jan 27 '16 at 20:34
18

Array Dereferencing is possible as of PHP 5.4:

Example (source):

function foo() {
    return array(1, 2, 3);
}
echo foo()[2]; // prints 3

with PHP 5.3 you'd get

Parse error: syntax error, unexpected '[', expecting ',' or ';' 

Original Answer:

This has been been asked already before. The answer is no. It is not possible.

To quote Andi Gutmans on this topic:

This is a well known feature request but won't be supported in PHP 5.0. I can't tell you if it'll ever be supported. It requires some research and a lot of thought.

You can also find this request a number of times in the PHP Bugtracker. For technical details, I suggest you check the official RFC and/or ask on PHP Internals.

Community
  • 1
  • 1
Gordon
  • 296,205
  • 68
  • 508
  • 534
  • 1
    Wow, nice work finding all those other versions of this question. I did look first, which, per the stackoverflow creators, means it's worth having another version of the question, to make it more googlable. – dreeves Nov 24 '09 at 05:43
  • **NOTE:** This question was incorrectly marked as "already asked" [array dereferencing](http://stackoverflow.com/questions/13109). **This question has not already been asked**, because it is not exclusively about arrays. A PHP function can return any value type, not just arrays (see example2 in the original post, where the function result is an object, and not an array). – dreftymac Apr 14 '15 at 15:34
14

Well, you could use any of the following solutions, depending on the situation:

function foo() {
    return array("foo","bar","foobar","barfoo","tofu");
}
echo(array_shift(foo())); // prints "foo"
echo(array_pop(foo())); // prints "tofu"

Or you can grab specific values from the returned array using list():

list($foo, $bar) = foo();
echo($foo); // prints "foo"
echo($bar); // print "bar"

Edit: the example code for each() I gave earlier was incorrect. each() returns a key-value pair. So it might be easier to use foreach():

foreach(foo() as $key=>$val) {
    echo($val);
}
Calvin
  • 4,257
  • 1
  • 22
  • 21
  • In PHP 5.5.10 it still throws the following error: "Strict standards: Only variables should be passed by reference in php". Ridiculous. – Zsolt Gyöngyösi Mar 30 '14 at 13:48
  • @ZsoltGyöngyösi, That error is present **way back in PHP 5.05.** See http://3v4l.org/voQIS . Also, performance note: `array_pop` may be fast because you need to simply remove the last element, but [`array_shift`](http://php.net/manual/en/function.array-shift.php) is incredibly slow because it needs to change **all** the number indexes by shifting them down by 1. – Pacerier Jul 20 '15 at 18:22
7

There isn't a way to do that unfortunately, although it is in most other programming languages.

If you really wanted to do a one liner, you could make a function called a() and do something like

$test = a(func(), 1); // second parameter is the key.

But other than that, func()[1] is not supported in PHP.

Tyler Carter
  • 57,335
  • 20
  • 122
  • 148
  • Oh wow, I didn't know that. Do you know why that doesn't work? Shouldn't func() be essentially an array type with the return value, so [1] acts on an array? Or does PHP parse it poorly? – thedz Jul 25 '09 at 16:43
  • PHP does not parse it like other languages do, so you have to define it as a variable first. – Tyler Carter Jul 25 '09 at 16:46
  • @Kouroki Kaze: array_slice still returns an array, even if the slice would result in a single value. You could combine it with current, but that's starting to get a bit long for a single line. ;-) – James Aug 19 '10 at 15:32
  • @James, It's long, but that's not the point. It's still one line and it works. – Pacerier Jul 20 '15 at 18:58
5

As others have mentioned, this isn't possible. PHP's syntax doesn't allow it. However, I do have one suggestion that attacks the problem from the other direction.

If you're in control of the getBarArray method and have access to the PHP Standard Library (installed on many PHP 5.2.X hosts and installed by default with PHP 5.3) you should consider returning an ArrayObject instead of a native PHP array/collection. ArrayObjects have an offetGet method, which can be used to retrieve any index, so your code might look something like

<?php
class Example {
    function getBarArray() {
        $array = new ArrayObject();
        $array[] = 'uno';
        $array->append('dos');
        $array->append('tres');
        return $array;
    }
}

$foo = new Example();
$value = $foo->getBarArray()->offsetGet(2);

And if you ever need a native array/collection, you can always cast the results.

//if you need 
$array = (array) $foo->getBarArray();
Alan Storm
  • 157,413
  • 86
  • 367
  • 554
5

If you just want to return the first item in the array, use the current() function.

return current($foo->getBarArray());

http://php.net/manual/en/function.current.php

Gordon
  • 296,205
  • 68
  • 508
  • 534
AntonioCS
  • 7,872
  • 17
  • 60
  • 90
  • 1
    No, there is no guarantee that `current` is **currently** pointing to the first element. See http://3v4l.org/OZLjR and http://3v4l.org/kEC9H for examples whereby blindly calling `current` will indeed give you the non-first item. **Whenever you call `current` you must first call [`reset`](http://php.net/reset)**, otherwise be prepared for trouble. – Pacerier Jul 20 '15 at 19:31
5

Write a wrapper function that will accomplish the same. Because of PHP's easy type-casting this can be pretty open-ended:

function array_value ($array, $key) {
return $array[$key];
}
Jason Plank
  • 2,322
  • 4
  • 29
  • 39
Nolte
  • 1,108
  • 5
  • 11
  • 2
    The most efficient function would use an array reference here. Example: `function array_value(&$a,$k) { $b = &$a; return $b[$k]; }` – KyleFarris Feb 16 '11 at 21:53
  • I think you can get the same result by just telling the function to return by reference, i.e. function &array_value (... – Nolte Jul 24 '11 at 20:19
  • @KyleFarris, I highly doubt that is more efficient now, nor even in the future. (There're also [test results here](http://stackoverflow.com/a/7787283/632951).) This is because 1) using array references when none is needed has been discouraged by language prescriptivists, and 2) current and future language implementors try to optimize general use cases, most of which are derived from such prescriptions. – Pacerier Jul 20 '15 at 19:28
3

Actually, I've written a library which allows such behavior:

http://code.google.com/p/php-preparser/

Works with everything: functions, methods. Caches, so being as fast as PHP itself :)

Valentin Golev
  • 9,653
  • 8
  • 57
  • 79
  • This is a comment, not an answer. There are 28 answers here. Visitors to this page will thank you if you can convert this answer to a comment. – Pacerier Jul 20 '15 at 18:40
3

You can't chain expressions like that in PHP, so you'll have to save the result of array_test() in a variable.

Try this:

function array_test() {
  return array(0, 1, 2);
}

$array = array_test();
echo $array[0];
ashrewdmint
  • 548
  • 3
  • 14
2

This is too far-fetched, but if you really NEED it to be in one line:


return index0( $foo->getBarArray() );

/* ... */

function index0( $some_array )
{
  return $some_array[0];
}

Petruza
  • 10,275
  • 24
  • 74
  • 121
2

After further research I believe the answer is no, a temporary variable like that is indeed the canonical way to deal with an array returned from a function.

Looks like this will change starting in PHP 5.4.

Also, this answer was originally for this version of the question:

How to avoid temporary variables in PHP when using an array returned from a function

Community
  • 1
  • 1
dreeves
  • 25,132
  • 42
  • 147
  • 226
  • There are 28 answers here. Visitors to this page will thank you if you can delete this answer so we have more signal and less noise. – Pacerier Jul 20 '15 at 18:38
2

You could, of course, return an object instead of an array and access it this way:

echo "This should be 2: " . test()->b ."\n";

But I didn't find a possibility to do this with an array :(

Pesse
  • 401
  • 3
  • 6
2

my usual workaround is to have a generic function like this

 function e($a, $key, $def = null) { return isset($a[$key]) ? $a[$key] : $def; }

and then

  echo e(someFunc(), 'key');

as a bonus, this also avoids 'undefined index' warning when you don't need it.

As to reasons why foo()[x] doesn't work, the answer is quite impolite and isn't going to be published here. ;)

user187291
  • 50,823
  • 18
  • 89
  • 127
  • 1
    Do you ever happen to find yourself looking at code that uses this technique, and wondering (even if just for a few milliseconds), "Now what does this do again?" – Ben Dunlap Nov 20 '09 at 18:13
  • 1
    This still creates a temporary (2 or 3, in fact), but they're in a lower scope an quickly go away, so that's a bonus. – outis Nov 20 '09 at 20:38
  • @BenDunlap, It's blackboxed. So it's the method name that counts. – Pacerier Jul 20 '15 at 18:37
  • @user187291, Why do you say "the answer is quite impolite"? – Pacerier Jul 20 '15 at 18:38
2

These are some ways to approach your problem.

First you could use to name variables directly if you return array of variables that are not part of the collection but have separate meaning each.

Other two ways are for returning the result that is a collection of values.

function test() {
  return array(1, 2);
}   
list($a, $b) = test();
echo "This should be 2: $b\n";

function test2() {
   return new ArrayObject(array('a' => 1, 'b' => 2), ArrayObject::ARRAY_AS_PROPS);
}
$tmp2 = test2();
echo "This should be 2: $tmp2->b\n";

function test3() {
   return (object) array('a' => 1, 'b' => 2);
}
$tmp3 = test3();
echo "This should be 2: $tmp3->b\n";
ivanjovanovic
  • 476
  • 4
  • 9
2

Extremely ghetto, but, it can be done using only PHP. This utilizes a lambda function (which were introduced in PHP 5.3). See and be amazed (and, ahem, terrified):

function foo() {
    return array(
        'bar' => 'baz',
        'foo' => 'bar',
}

// prints 'baz'
echo call_user_func_array(function($a,$k) { 
    return $a[$k]; 
}, array(foo(),'bar'));

The lengths we have to go through to do something so beautiful in most other languages.

For the record, I do something similar to what Nolte does. Sorry if I made anyone's eyes bleed.

KyleFarris
  • 16,408
  • 4
  • 40
  • 40
  • `call_user_func` alone will work: http://3v4l.org/qIbtp. We don't need `call_user_func_array`. Btw, "ghetto" mean many things... what would "ghetto" mean here? – Pacerier Jul 20 '15 at 19:14
  • Man, that was like 4.5 years ago. Who know what I was thinking then? Probably just meant something like "put together with ducktape and string". – KyleFarris Jul 21 '15 at 20:19
1

Short Answer:

Yes. It is possible to operate on the return value of a function in PHP, so long as the function result and your particular version of PHP support it.

Referencing example2:

//  can php say "homer"?      
//  print zoobar()->fname;     //  homer <-- yup

Cases:

  • The function result is an array and your PHP version is recent enough
  • The function result is an object and the object member you want is reachable
dreftymac
  • 27,818
  • 25
  • 108
  • 169
1

If it is just aesthetic, then the Object notation will work if you return an object. As far as memory management goes, no temporary copy if made, only a change in reference.

bucabay
  • 4,909
  • 2
  • 22
  • 34
1

Previously in PHP 5.3 you had to do this:

function returnArray() {
  return array(1, 2, 3);
}
$tmp = returnArray();
$ssecondElement = $tmp[1];

Result: 2

As of PHP 5.4 it is possible to dereference an array as follows:

function returnArray() {
  return array(1, 2, 3);
}
$secondElement = returnArray()[1];

Result: 2

As of PHP 5.5:

You can even get clever:

echo [1, 2, 3][1];

Result: 2

You can also do the same with strings. It's called string dereferencing:

echo 'PHP'[1];

Result: H

Robert Rocha
  • 8,656
  • 15
  • 59
  • 110
1

There are three ways to do the same thing:

  1. As Chacha102 says, use a function to return the index value:

    function get($from, $id){
        return $from[$id];
    }
    

    Then, you can use:

    get($foo->getBarArray(),0);
    

    to obtain the first element and so on.

  2. A lazy way using current and array_slice:

    $first = current(array_slice($foo->getBarArray(),0,1));
    $second = current(array_slice($foo->getBarArray(),1,1));
    
  3. Using the same function to return both, the array and the value:

    class FooClass {
        function getBarArray($id = NULL) {
            $array = array();
    
            // Do something to get $array contents
    
            if(is_null($id))
                return $array;
            else
                return $array[$id];
            }
    }
    

    Then you can obtain the entire array and a single array item.

    $array = $foo->getBarArray();
    

    or

    $first_item = $foo->getBarArray(0);
    
Pacerier
  • 76,400
  • 86
  • 326
  • 602
Andrés Morales
  • 773
  • 7
  • 20
  • 1
    `current(array_slice($arr, $offset, 1))` is good. Because the new array has just been created and there are no leaking variable references to it, `current` is **guaranteed** ([by the specs](http://php.net/current)) to point to the first element without the need to call `reset`. – Pacerier Jul 20 '15 at 19:03
0

Does this work?

 return ($foo->getBarArray())[0];

Otherwise, can you post the getBarArray() function? I don't see why that wouldn't work from what you posted so far.

thedz
  • 5,284
  • 2
  • 22
  • 28
  • 1
    No that doesn't work either. Regardless of the function, it throws an "unexpected [" error. – James Skidmore Jul 25 '09 at 16:39
  • There are 28 answers here. Visitors to this page will thank you if you can delete this answer (actually, **this is not even an answer**) so we have more signal and less noise. – Pacerier Jul 20 '15 at 19:06
0

You could use references:

$ref =& myFunc();
echo $ref['foo'];

That way, you're not really creating a duplicate of the returned array.

mattbasta
  • 12,633
  • 9
  • 41
  • 67