PHP syntax for dereferencing function result
Asked Answered
F

22

36

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     
Fogbow answered 13/4, 2009 at 1:12 Comment(4)
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)...Ramiah
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).Fogbow
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). The runner-up prize goes to current(array_slice($arr, $offset, 1)).Nidanidaros
@Nidanidaros 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.Benoit
D
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!

Deery answered 25/10, 2011 at 12:41 Comment(2)
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).Fogbow
@Fogbow In PHP 7 this was cleaned up finally and you can now use a function call in any expression.Rimple
C
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]);
Clammy answered 13/4, 2009 at 1:14 Comment(9)
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 newMishamishaan
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.Passionate
I honestly don't know why this is the case but it is.Reahard
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?Fogbow
@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.Keilakeily
@Ó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.Keilakeily
@vartec, what array dereferencing has to do with OOP?Zenia
Really, the language seems consistent on allowing fluent usage of results, so why not with arrays? Seems like they agreed.Winegar
@Ó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.Nidanidaros
D
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!

Deery answered 25/10, 2011 at 12:41 Comment(2)
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).Fogbow
@Fogbow In PHP 7 this was cleaned up finally and you can now use a function call in any expression.Rimple
R
19

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.

Renferd answered 22/11, 2009 at 17:1 Comment(2)
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.Rousing
NOTE: This question was incorrectly marked as "already asked" array dereferencing. 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).Fogbow
G
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);
}
Guise answered 13/4, 2009 at 2:36 Comment(2)
In PHP 5.5.10 it still throws the following error: "Strict standards: Only variables should be passed by reference in php". Ridiculous.Affirmative
@ZsoltGyöngyösi, That error is present way back in PHP 5.05. See 3v4l.org/voQIS . Also, performance note: array_pop may be fast because you need to simply remove the last element, but array_shift is incredibly slow because it needs to change all the number indexes by shifting them down by 1.Nidanidaros
T
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.

Tweet answered 25/7, 2009 at 16:36 Comment(4)
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?Diamagnet
PHP does not parse it like other languages do, so you have to define it as a variable first.Tweet
@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. ;-)Wendt
@James, It's long, but that's not the point. It's still one line and it works.Nidanidaros
H
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];
}
Hardunn answered 7/6, 2009 at 10:23 Comment(3)
The most efficient function would use an array reference here. Example: function array_value(&$a,$k) { $b = &$a; return $b[$k]; }Benoit
I think you can get the same result by just telling the function to return by reference, i.e. function &array_value (...Hardunn
@KyleFarris, I highly doubt that is more efficient now, nor even in the future. (There're also test results here.) 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.Nidanidaros
D
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();
Daff answered 25/7, 2009 at 17:44 Comment(0)
B
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

Barnes answered 31/7, 2009 at 16:3 Comment(1)
No, there is no guarantee that current is currently pointing to the first element. See 3v4l.org/OZLjR and 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, otherwise be prepared for trouble.Nidanidaros
D
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 :)

Denishadenison answered 1/11, 2009 at 2:29 Comment(1)
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.Nidanidaros
B
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];
Barney answered 17/2, 2010 at 15:50 Comment(0)
F
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];
}

Fosdick answered 25/7, 2009 at 16:56 Comment(0)
R
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

Rousing answered 20/11, 2009 at 8:23 Comment(1)
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.Nidanidaros
A
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 :(

Annoy answered 20/11, 2009 at 8:38 Comment(0)
C
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. ;)

Cermet answered 20/11, 2009 at 9:44 Comment(4)
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?"Involuted
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.Cony
@BenDunlap, It's blackboxed. So it's the method name that counts.Nidanidaros
@user187291, Why do you say "the answer is quite impolite"?Nidanidaros
P
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";
Parget answered 20/11, 2009 at 20:31 Comment(0)
B
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.

Benoit answered 16/2, 2011 at 22:34 Comment(2)
call_user_func alone will work: 3v4l.org/qIbtp. We don't need call_user_func_array. Btw, "ghetto" mean many things... what would "ghetto" mean here?Nidanidaros
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".Benoit
N
2

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

Negation answered 24/5, 2017 at 21:51 Comment(1)
Been working with PHP for a long time and I didn't realize until now that echo [1, 2, 3][1] was a thing. Thanks for the education, friend!Dick
L
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.

Laniferous answered 20/11, 2009 at 8:51 Comment(0)
W
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);
    
Whiteness answered 4/3, 2011 at 16:35 Comment(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) to point to the first element without the need to call reset.Nidanidaros
F
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
Fogbow answered 3/4, 2013 at 17:39 Comment(0)
D
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.

Diamagnet answered 25/7, 2009 at 16:35 Comment(2)
No that doesn't work either. Regardless of the function, it throws an "unexpected [" error.Blume
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.Nidanidaros
D
0

You could use references:

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

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

Dilantin answered 22/11, 2009 at 15:41 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.