Синтаксис PHP для результата разыменования функции

Фон

В любом другом языке программирования, который я использую на регулярной основе, легко работать с возвращаемым значением функции без объявления новой переменной для хранения результата функции.

В PHP, однако, это не так просто:

example1 (результат функции - массив)

<?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 (результатом функции является объект)

<?php    
function zoobar(){
  // NOTE: casting (object) Array() has other problems in PHP
  // see e.g., http://stackru.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     

Кто-нибудь может подсказать, как это сделать на PHP?

22 ответа

Решение

В частности, это разыменование массива, которое в настоящее время не поддерживается в php5.3, но должно стать возможным в следующем выпуске 5.4. С другой стороны, разыменование объектов возможно в текущих версиях php. Я также с нетерпением жду этой функциональности!

PHP не может получить доступ к результатам массива из функции. Некоторые люди называют это проблемой, некоторые просто принимают это как то, как устроен язык. Так что PHP заставляет вас создавать необязательные переменные просто для извлечения нужных вам данных.

Так что вам нужно сделать.

$var = foobar();
print($var[0]);

Разыменование массива возможно с PHP 5.4:

Пример ( источник):

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

с PHP 5.3 вы получите

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

Оригинальный ответ:

Об этом уже спрашивали. Ответ - нет. Это невозможно.

Чтобы процитировать Энди Гутманс на эту тему:

Это хорошо известный запрос, но он не будет поддерживаться в PHP 5.0. Я не могу сказать вам, будет ли это когда-либо поддержано. Это требует некоторых исследований и много размышлений.

Вы также можете найти этот запрос несколько раз в PHP Bugtracker. Для технических деталей, я предлагаю вам проверить официальный RFC и / или спросить на PHP Internals.

Ну, вы можете использовать любое из следующих решений, в зависимости от ситуации:

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

Или вы можете получить конкретные значения из возвращенного массива, используя list ():

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

Изменить: пример кода для каждого (), который я дал ранее, был неверным. each () возвращает пару ключ-значение. Так что может быть проще использовать foreach ():

foreach(foo() as $key=>$val) {
    echo($val);
}

К сожалению, нет способа сделать это, хотя это есть в большинстве других языков программирования.

Если вы действительно хотите сделать один вкладыш, вы можете сделать функцию с именем () и сделать что-то вроде

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

Но кроме этого, func()[1] не поддерживается в PHP.

Напишите функцию-обертку, которая выполнит то же самое. Из-за простоты приведения типов в PHP это может быть довольно открытым:

function array_value ($array, $key) {
return $array[$key];
}

Как уже упоминали другие, это невозможно. Синтаксис PHP не позволяет этого. Однако у меня есть одно предположение, которое решает проблему с другой стороны.

Если вы контролируете getBarArray метод и иметь доступ к стандартной библиотеке PHP (установленной на многих хостах PHP 5.2.X и установленной по умолчанию с PHP 5.3), вам следует рассмотреть возможность возврата ArrayObject вместо собственного массива / коллекции PHP. ArrayObjects есть offetGet метод, который можно использовать для получения любого индекса, поэтому ваш код может выглядеть примерно так

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

И если вам когда-нибудь понадобится собственный массив / коллекция, вы всегда можете привести результаты.

//if you need 
$array = (array) $foo->getBarArray();

Если вы просто хотите вернуть первый элемент в массиве, используйте функцию current().

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

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

Вы не можете связать такие выражения в PHP, поэтому вам придется сохранить результат array_test() в переменной.

Попробуй это:

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

$array = array_test();
echo $array[0];

На самом деле, я написал библиотеку, которая позволяет такое поведение:

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

Работает со всем: функциями, методами. Кэши, так же быстро, как и сам PHP:)

Ранее в PHP 5.3 вы должны были сделать это:

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

Результат: 2

Начиная с PHP 5.4, можно разыменовать массив следующим образом:

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

Результат: 2

Начиная с PHP 5.5:

Вы можете даже стать умным:

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

Результат: 2

Вы также можете сделать то же самое со строками. Это называется разыменованием строк:

echo 'PHP'[1];

Результат: H

Конечно, вы можете вернуть объект вместо массива и получить к нему доступ таким образом:

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

Но я не нашел возможности сделать это с массивом:(

После дальнейших исследований я считаю, что ответ "нет", такая временная переменная действительно является каноническим способом работы с массивом, возвращаемым функцией.

Похоже, это изменится, начиная с PHP 5.4.

Кроме того, этот ответ был первоначально для этой версии вопроса:

Как избежать временных переменных в PHP при использовании массива, возвращаемого функцией

Это слишком надумано, но если вам действительно нужно, чтобы это было в одной строке:


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

/* ... */

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

Вот несколько способов подойти к вашей проблеме.

Во-первых, вы можете использовать для именования переменных напрямую, если вы возвращаете массив переменных, которые не являются частью коллекции, но имеют отдельное значение для каждой.

Два других способа - вернуть результат, представляющий собой набор значений.

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

Мой обычный обходной путь должен иметь общую функцию, как это

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

а потом

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

в качестве бонуса это также позволяет избежать предупреждения "неопределенный индекс", когда оно вам не нужно.

Что касается причин, почему foo()[x] не работает, ответ довольно невежлив и не будет опубликован здесь.;)

Чрезвычайно гетто, но это можно сделать, используя только PHP. При этом используется лямбда-функция (которая была введена в PHP 5.3). Смотри и удивляйся (и, гм, в ужасе):

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

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

Сколько нужно пройти, чтобы сделать что-то прекрасное на большинстве других языков.

Для протокола, я делаю что-то похожее на то, что делает Нольте. Извините, если я заставил чьи-то глаза кровоточить.

Если это просто эстетично, то запись Object будет работать, если вы вернете объект. Что касается управления памятью, никакое временное копирование, если оно сделано, только изменение ссылки.

Есть три способа сделать то же самое:

  1. Как говорит Chacha102, используйте функцию для возврата значения индекса:

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

    Затем вы можете использовать:

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

    получить первый элемент и так далее.

  2. Ленивый способ с использованием current и array_slice:

    $first = current(array_slice($foo->getBarArray(),0,1));
    $second = current(array_slice($foo->getBarArray(),1,1));
    
  3. Используя одну и ту же функцию, вы получите и массив, и значение:

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

    Затем вы можете получить весь массив и один элемент массива.

    $array = $foo->getBarArray();
    

    или же

    $first_item = $foo->getBarArray(0);
    

Короткий ответ:

Да. Можно работать с возвращаемым значением функции в PHP, если только результат функции и ваша конкретная версия PHP поддерживают его.

Ссылка на пример2:

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

случаи:

  • Результатом функции является массив, а ваша версия PHP достаточно свежая
  • Результатом функции является объект, и требуемый член объекта доступен

Вы можете использовать ссылки:

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

Таким образом, вы на самом деле не создаете дубликат возвращаемого массива.

Это работает?

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

В противном случае, вы можете опубликовать функцию getBarArray()? Я не понимаю, почему это не сработает из того, что вы опубликовали до сих пор.

Другие вопросы по тегам