PHP syntax for dereferencing function result

2019-01-07 00:23发布

问题:

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     

Can anyone suggest how to do this in PHP?

回答1:

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!



回答2:

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]);


回答3:

Array Dereferencing is possible as of PHP 5.4:

  • http://svn.php.net/viewvc?view=revision&revision=300266

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.



回答4:

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);
}


回答5:

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.



回答6:

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();


回答7:

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];
}


回答8:

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



回答9:

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 :)



回答10:

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];


回答11:

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];
}



回答12:

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 :(



回答13:

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. ;)



回答14:

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";


回答15:

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.



回答16:

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



回答17:

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.



回答18:

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


回答19:

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);
    


回答20:

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



回答21:

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.



回答22:

You could use references:

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

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