Многократный возврат из функции


198

Возможно ли иметь функцию с двумя возвратами, например так:

function test($testvar)
{
  // Do something

  return $var1;
  return $var2;
}

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


1
Что именно вы пытаетесь достичь? Конечно, если вы объяснили свою реальную проблему, кто-то здесь может помочь вам найти элегантное решение.
Майк Дэниелс

3
Вопрос не делает различий между одним или двумя значениями, двумя или двумя значениями, или новой концепцией ленивой оценки, а затем, возможно, двумя из двух значений. Первый тривиален с любым условным потоком. Второе разрешено в python: q, r = divmod (x, y); а также Лисп; PHP требует список ($ q, $ r) = twovals (); хак, где функция twovals () {вернуть массив ($ a, $ b); }. Ленивая оценка довольно продвинута и еще не завоевала популярность в PHP. Поскольку вопрос не является точным, рекомендуем не использовать эту запись в качестве окончательного справочного материала по этой теме.
DragonLord

5
Если вам нужны оба значения, верните их в массив.
Бхаргав Нанекалва

2
@DragonLord в PHP 7.1, вы можете использовать синтаксис короткого списка
Янус Троелсен

1
Существует повторяющийся вопрос, но с более краткими ответами, поэтому он поможет вам быстрее перейти к сути: вернуть 2 значения из функции .
Дважды Гра

Ответы:


162

Нет способа вернуть 2 переменные. Хотя вы можете распространять массив и возвращать его; создать условие для возврата динамической переменной и т. д.

Например, эта функция вернет $var2

function wtf($blahblah = true) {
    $var1 = "ONe";
    $var2 = "tWo";

    if($blahblah === true) {
      return $var2;
    }
    return $var1;
}

В приложении:

echo wtf();
//would echo: tWo
echo wtf("not true, this is false");
//would echo: ONe

Если вы хотите их обоих, вы можете немного изменить функцию

function wtf($blahblah = true) {
    $var1 = "ONe";
    $var2 = "tWo";

    if($blahblah === true) {
      return $var2;
    }

    if($blahblah == "both") {
      return array($var1, $var2);
    }

    return $var1;
}

echo wtf("both")[0]
//would echo: ONe
echo wtf("both")[1]
//would echo: tWo

list($first, $second) = wtf("both")
// value of $first would be $var1, value of $second would be $var2

15
Если бы только PHP имел Perlwantarray()
Marc B

6
ИМХО, этот ответ был бы улучшен, если бы он пропустил первую часть, в которой обсуждается, как вернуть одно или другое значение в зависимости от некоторого условия. Я уверен, что 99,999% людей, пришедших на это обсуждение, хотят знать, как вернуть оба значения одновременно. Смотрите самый высоко оцененный ответ.
ToolmakerSteve

401

Технически, вы не можете вернуть более одного значения. Однако существует несколько способов обойти это ограничение. Способ, который действует как возвращение нескольких значений, с listключевым словом:

function getXYZ()
{
    return array(4,5,6);
}

list($x,$y,$z) = getXYZ();

// Afterwards: $x == 4 && $y == 5 && $z == 6
// (This will hold for all samples unless otherwise noted)

Технически, вы возвращаете массив и используете listдля хранения элементов этого массива в разных значениях вместо хранения фактического массива. Использование этой техники позволит почувствовать наиболее как возвращение нескольких значений.

listРешение является весьма PHP конкретным один. Есть несколько языков с похожей структурой, но больше языков, которые этого не делают. Есть другой способ, который обычно используется для «возврата» нескольких значений, и он доступен практически на каждом языке (так или иначе). Тем не менее, этот метод будет выглядеть совсем по-другому, поэтому может потребоваться привыкнуть.

// note that I named the arguments $a, $b and $c to show that
// they don't need to be named $x, $y and $z
function getXYZ(&$a, &$b, &$c)
{
    $a = 4;
    $b = 5;
    $c = 6; 
}

getXYZ($x, $y, $z);

Этот метод также используется в некоторых функциях, определенных самим php (например, $countв str_replace , $matchesв preg_match ). Это может показаться совершенно отличным от возврата нескольких значений, но об этом стоит хотя бы знать.

Третий метод - использовать объект для хранения разных значений, которые вам нужны. Это больше печатать, поэтому он используется не так часто, как два метода выше. Возможно, имеет смысл использовать это, когда используется один и тот же набор переменных в нескольких местах (или, конечно, работа на языке, который не поддерживает вышеуказанные методы или позволяет вам делать это без дополнительной типизации).

class MyXYZ
{
    public $x;
    public $y;
    public $z;
}

function getXYZ()
{
    $out = new MyXYZ();

    $out->x = 4;
    $out->y = 5;
    $out->z = 6;

    return $out;
}

$xyz = getXYZ();

$x = $xyz->x;
$y = $xyz->y;
$z = $xyz->z;

Вышеуказанные методы суммируют основные способы возврата нескольких значений из функции. Однако существуют варианты этих методов. Наиболее интересные варианты - это те, в которых вы на самом деле возвращаете массив, просто потому, что в PHP вы так много можете сделать с массивами.

Во-первых, мы можем просто вернуть массив и не рассматривать его как что-либо, кроме массива:

function getXYZ()
{
    return array(1,2,3);
}

$array = getXYZ();

$x = $array[1];
$y = $array[2];
$z = $array[3];

Самая интересная часть кода выше - то, что код внутри функции такой же, как в самом первом примере, который я предоставил; изменился только код, вызывающий функцию. Это означает, что обработчик результата возвращает функцию, вызывающую функцию.

В качестве альтернативы можно использовать ассоциативный массив:

function getXYZ()
{
    return array('x' => 4,
                 'y' => 5,
                 'z' => 6);
}

$array = getXYZ();

$x = $array['x'];
$y = $array['y'];
$z = $array['z'];

Php имеет compactфункцию, которая позволяет вам делать то же, что и выше, но при написании меньшего количества кода. (Ну, в примере не будет меньше кода, но, вероятно, в реальном приложении.) Однако, я думаю, что экономия при наборе текста минимальна, и это затрудняет чтение кода, поэтому я бы не стал делать это сам. Тем не менее, вот пример:

function getXYZ()
{
    $x = 4;
    $y = 5;
    $z = 6;

    return compact('x', 'y', 'z');
}

$array = getXYZ();

$x = $array['x'];
$y = $array['y'];
$z = $array['z'];

Следует отметить, что хотя compactесть аналог вextract который можно было бы использовать здесь в вызывающем коде, но поскольку его использование является плохой идеей (особенно для чего-то столь же простого, как это), я даже не буду приводить пример для него. Проблема в том, что он будет делать «магию» и создавать переменные для вас, в то время как вы не сможете увидеть, какие переменные созданы, не переходя к другим частям кода.

Наконец, я хотел бы отметить, что с ассоциативным массивом listне очень хорошо. Следующее будет делать то, что вы ожидаете:

function getXYZ()
{
    return array('x' => 4,
                 'y' => 5,
                 'z' => 6);
}

$array = getXYZ();

list($x, $y, $z) = getXYZ();

Однако следующее сделает что-то другое:

function getXYZ()
{
    return array('x' => 4,
                 'z' => 6,
                 'y' => 5);
}

$array = getXYZ();

list($x, $y, $z) = getXYZ();

// Pay attention: $y == 6 && $z == 5

Если вы использовали listс ассоциативным массивом, и кто-то другой должен изменить код вызываемой функции в будущем (что может произойти практически в любой ситуации), он может внезапно сломаться, поэтому я бы рекомендовал не комбинировать listс ассоциативными массивами.


2
Также: return compact ('var1', 'var2', 'var3');
Бьюдсон

1
Это еще один вариант, но я не чувствую, что возвращаю несколько значений, как возвращаю массив. Это может быть только я, хотя. Лично я бы нашел return array('x' => $x, 'y' => $y, 'z' => $z)чище, но до того момента, когда я сам это напишу, а не до того, чтобы попросить других использовать этот формат.
Джаспер

2
Использование List () - отличный ответ на симуляционную проблему, с которой я столкнулся. это отличный способ проверки и возврата нескольких переменных обратно в функцию. Беглый взгляд на документацию по php позволит пролить больше света на эту функцию и, возможно, сделает ее более понятной. php.net/manual/en/function.list.php .. спасибо Джаспер!
JustinP

2
+1 за такой обширный ответ, особенно на такой широкий, общий вопрос. Несмотря на это, этот ответ очень помог мне.
Ли Блейк

2
@Mikey Исторические причины. Этот ответ был первоначально опубликован на другой вопрос, который был удален за точную копию этого вопроса (несмотря на тот факт, что он был на самом деле старше). Ответ на этот вопрос был перенесен позже, чем последний визит того, кто задал этот вопрос.
Джаспер

73

В вашем примере второе возвращение никогда не произойдет - первое возвращение - это последнее, что PHP запустит. Если вам нужно вернуть несколько значений, верните массив:

function test($testvar) {

    return array($var1, $var2);
}

$result = test($testvar);
echo $result[0]; // $var1
echo $result[1]; // $var2

18
Вы также можете сделать:list($result_1, result_2) = test($testvar);
Тим Купер

@ Тим Купер: result_2или $result_2?
Питер Мортенсен

@PeterMortensen:$result_2
Тим Купер

46

Начиная с PHP 7.1 мы имеем правильную деструктуризацию для списков. Тем самым вы можете делать такие вещи:

$test = [1, 2, 3, 4];
[$a, $b, $c, $d] = $test;
echo($a);
> 1
echo($d);
> 4

В функции это будет выглядеть так:

function multiple_return() {
    return ['this', 'is', 'a', 'test'];
}

[$first, $second, $third, $fourth] = multiple_return();
echo($first);
> this
echo($fourth);
> test

Разрушение - очень мощный инструмент. Он также способен деструктурировать пары ключ => значение:

["a" => $a, "b" => $b, "c" => $c] = ["a" => 1, "b" => 2, "c" => 3];

Взгляните на новую страницу возможностей для PHP 7.1:

Новые особенности


5
Я бы хотел, чтобы в StackOverflow была функция «избранный ответ», даже если она не была принята ко времени создания вопроса, потому что этот ответ довольно полезен и обновлен, но, конечно, не по теме.
Джонатас CD

3
@JonatasCD - не уверен, почему вы говорите, что этот ответ "не по теме". В PHP 7.1 это является наиболее удобным способом для создания и обработок несколько возвращаемых значений из функции. Таким образом, для более новых версий PHP, это лучший ответ на первоначальный принятый ответ.
ToolmakerSteve

@ ToolmakerSteve Я думаю, вы меня не поняли. «не по теме» вопроса было мое предложение изменить то, что было принято, исходя из будущих реализаций. Это не было ничего против твоего ответа;)
Jonatas CD

@JonatasCD - А, это объясняет. (Разве это не мой ответ, я был просто озадачен.) По крайней мере, тег, который говорит: «Это более актуально, чем принятый ответ». Может быть, три человека должны согласиться с этим тегом, и тогда он станет признаком. :)
ToolmakerSteve

26

В PHP 5.5 есть также новая концепция: generatorsгде вы можете получить несколько значений из функции:

function hasMultipleValues() {
    yield "value1";
    yield "value2";
}

$values = hasMultipleValues();
foreach ($values as $val) {
    // $val will first be "value1" then "value2"
}

16

Или вы можете пройти по ссылке:

function byRef($x, &$a, &$b)
{
    $a = 10 * $x;
    $b = 100 * $x;
}

$a = 0;
$b = 0;

byRef(10, $a, $b);

echo $a . "\n";
echo $b;

Это будет вывод

100
1000

9

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

function test()
{
    return [ 'model' => 'someValue' , 'data' => 'someothervalue'];
}

Теперь вы можете использовать это

$result = test();
extract($result);

extractсоздает переменную для каждого члена в массиве, названную в честь этого члена. Теперь вы можете получить доступ $modelи$data


1
ПРИМЕЧАНИЕ: будьте осторожны, чтобы ключи (здесь modelи data) не существовали как переменные. Если это так, используйте prefixпараметр, extractчтобы избежать конфликтов.
ToolmakerSteve

7

Вы можете вернуть несколько массивов и скаляров из функции

function x()
{
    $a=array("a","b","c");
    $b=array("e","f");
    return array('x',$a,$b);
}

list ($m,$n,$o)=x();

echo $m."\n";
print_r($n);
print_r($o);

7

Невозможно иметь два оператора возврата. Однако это не выдает ошибку, но при вызове функции вы получите только первое возвращаемое значение оператора. Мы можем использовать возврат массива, чтобы получить несколько значений взамен. Например:

function test($testvar)
{
  // do something
  //just assigning a string for example, we can assign any operation result
  $var1 = "result1";
  $var2 = "result2";
  return array('value1' => $var1, 'value2' => $var2);
}

5

Функции по определению возвращают только одно значение.

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

Так что вы можете сделать что-то вроде:

<?PHP
function myfunc($a,$b){
   return array('foo'=>$a,'bar'=>$b);
}
print_r(myfunc('baz','bork'));

Тем не менее, стоит уделить минутку и подумать о том, что вы пытаетесь решить. Хотя возвращение комплексного значения результата (например, массива или объекта) вполне допустимо, если вы думаете, что «я хочу вернуть два значения», вы можете плохо проектировать. Трудно сказать без подробностей в вашем вопросе, но никогда не повредит остановиться и подумать дважды.


5

Рекомендуется поместить возвращаемые переменные в массив, а затем использовать их list()для присвоения значений массива переменным.

<?php

function add_subt($val1, $val2) {
    $add = $val1 + $val2;
    $subt = $val1 - $val2;

    return array($add, $subt);
}

list($add_result, $subt_result) = add_subt(20, 7);
echo "Add: " . $add_result . '<br />';
echo "Subtract: " . $subt_result . '<br />';

?>

5

Да, вы можете использовать объект :-)

Но самый простой способ - вернуть массив:

return array('value1', 'value2', 'value3', '...');

5

Для PHP 7.1 <= вы можете использовать новый синтаксис (вместо функции списка ):

/**
* @return  array  [foo, bar]
*/
function getFooAndBar(): array {
    return ['foo', 'bar'];
}

[$foo, $bar] = getFooAndBar();

print 'Hello '. $foo . ' and ' . $bar;

Это нормально для меня, если вы хотите вернуть 2-3 переменные, в противном случае вы должны использовать объект с желаемыми свойствами.


4

Я реализовал, как это для функции PHP множественного возвращаемого значения. будь хорош с твоим кодом. Спасибо.

 <?php
    function multi_retun($aa)
    {
        return array(1,3,$aa);
    }
    list($one,$two,$three)=multi_retun(55);
    echo $one;
    echo $two;
    echo $three;
    ?>

4

Ответ с зеленой галочкой выше на самом деле неверен. Вы можете вернуть несколько значений в PHP, если вы возвращаете массив. Смотрите следующий код для примера:

<?php

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

list ($zero, $one, $two) = small_numbers();

Этот код фактически скопирован со следующей страницы на веб-сайте PHP: http://php.net/manual/en/functions.returning-values.php Я также сам много раз использовал один и тот же код, так что могу подтвердить, что это хорошо, и это работает.


Этот ответ относится к примеру кода в вопросе, поэтому он не является строго неверным. Но вопрос неоднозначный. Намерение , вероятно, состоит в том, чтобы вернуть два значения из одного вызова функции.
Питер Мортенсен

3

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


3

Думал, что я бы расширил несколько ответов сверху ....

class nameCheck{

public $name;

public function __construct(){
    $this->name = $name;
}

function firstName(){
            // If a name has been entered..
    if(!empty($this->name)){
        $name = $this->name;
        $errflag = false;
                    // Return a array with both the name and errflag
        return array($name, $errflag);
            // If its empty..
    }else if(empty($this->name)){
        $errmsg = 'Please enter a name.';
        $errflag = true;
                    // Return both the Error message and Flag
        return array($errmsg, $errflag);
    }
}

}


if($_POST['submit']){

$a = new nameCheck;
$a->name = $_POST['name'];
//  Assign a list of variables from the firstName function
list($name, $err) = $a->firstName();

// Display the values..
echo 'Name: ' . $name;
echo 'Errflag: ' . $err;
}

?>
<form method="post" action="<?php $_SERVER['PHP_SELF']; ?>" >
<input name="name"  />
<input type="submit" name="submit" value="submit" />
</form>

Это даст вам поле ввода и кнопку отправки после отправки. Если поле ввода имени пусто, оно вернет флаг ошибки и сообщение. Если поле имени имеет значение, оно вернет значение / имя и флаг ошибки 0 для false = нет ошибок. Надеюсь это поможет!


3

Некоторые могут предпочесть возврат нескольких значений как объекта:

function test() {
    $object = new stdClass();

    $object->x = 'value 1';
    $object->y = 'value 2';

    return $object;
}

И назовите это так:

echo test()->x;

Или:

$test = test();
echo $test->y;

3

Да и нет. Вы не можете вернуть более одной переменной / объекта, но, как вы предлагаете, вы можете поместить их в массив и вернуть это.

Нет ограничений на вложение массивов, так что вы можете просто упаковать их таким образом, чтобы они возвращались.


2

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


1

Ответ - нет. Когда синтаксический анализатор достигает первого оператора возврата, он перенаправляет управление обратно к вызывающей функции - ваш второй оператор возврата никогда не будет выполнен.


Строго говоря, да. Но вопрос неоднозначный. Возможно, целью было вернуть два значения из одного вызова функции.
Питер Мортенсен

1

Добавьте все переменные в массив и, наконец, верните array.

function test($testvar)
{
  // do something
  return array("var1" => $var1, "var2" => @var2);
}

А потом

$myTest = test($myTestVar);
//$myTest["var1"] and $myTest["var2"] will be usable

1

Я думаю, что Элиего четко объяснил ответ. Но если вы хотите вернуть оба значения, поместите их в массив и верните его.

function test($testvar)
{
  // do something

  return array('var1'=>$var1,'var2'=>$var2);
//defining a key would be better some times   
}

// для доступа к возвращаемым значениям

$returned_values = test($testvar);

echo $returned_values['var1'];
echo $returned_values['var2'];

Вы были трезвым, когда написали это? Я могу сразу заметить 2 ошибки. 1) Вы используете $thisключевое слово, но не упоминается ни класс, ни объект. 2) Если вы вернули значения в свою переменную $returned_values, то вы должны повторить эту переменную:echo $returned_values['var1'];
dading84

исправил проблему.
Гихан де Сильва

0
<?php
function foo(){
  $you = 5;
  $me = 10;
  return $you;
  return $me;
}

echo foo();
//output is just 5 alone so we cant get second one it only retuns first one so better go with array


function goo(){
  $you = 5;
  $me = 10;
  return $you_and_me =  array($you,$me);
}

var_dump(goo()); // var_dump result is array(2) { [0]=> int(5) [1]=> int(10) } i think thats fine enough

?>

0

Языки, которые допускают множественные возвраты, обычно просто конвертируют множественные значения в структуру данных.

Например, в Python вы можете вернуть несколько значений. Тем не менее, они на самом деле просто возвращаются как один кортеж.

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


0

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

function t(&$a, &$b) {
    $a = 1;
    $b = 2;
}


t($a, $b);

echo $a . '  ' . $b;

Вывод:

1 2

Re «получить значения двух или более переменных» : Вы имеете в виду «вернуть значения двух или более переменных» ?
Питер Мортенсен

0

PHP все еще использует "параметры out"? Если это так, вы можете использовать синтаксис для изменения одного или нескольких параметров, входящих в вашу функцию. После этого вы сможете использовать измененную переменную после возврата из функции.


-1

Это самый простой способ сделать это:

public function selectAllUsersByRole($userRole, $selector) {

    $this->userRole = $userLevel;
    $this->selector = $selector;

    $sql = "SELECT * FROM users WHERE role <= ? AND del_stat = 0";
    $stm = $this->connect()->prepare($sql); // Connect function in Dbh connect to database file
    $stm->execute([$this->userRole]); // This is PHP 7. Use array($this->userRole) for PHP 5

    $usersIdArray = array();
    $usersFNameArray = array();
    $usersLNameArray = array();

    if($stm->rowCount()) {
        while($row = $stm->fetch()) {

            array_push($usersIdArray,    $row['id']);
            array_push($usersFNameArray, $row['f_name']);
            array_push($usersLNameArray, $row['l_name']);

            // You can return only $row['id'] or f_name or ...
            // I used the array because it's most used.
        }
    }
    if($this->selector == 1) {
        return $usersIdArray;
    }elseif($this->selector == 2) {
        return $usersFNameArray;
    }elseif($this->selector == 3) {
        return $usersLNameArray;
    }

}

Как мы можем вызвать эту функцию?

$idData = $selectAllUsers->selectAllUsersByLevel($userRole, 0);
print_r($idData);
$idFName = $selectAllUsers->selectAllUsersByLevel($userRole, 1);
print_r($idFname);

Вот и все. Очень просто.


-1
$var1 = 0;
$var2 = 0;

function test($testvar, &$var1 , &$var2)
{
  $var1 = 1;
  $var2 = 2;
  return;
}
test("", $var1, $var2);

// var1 = 1, var2 = 2 

Это не очень хороший способ, но я думаю, что мы можем установить две переменные в функции одновременно.


-4

У меня была похожая проблема - поэтому я попытался и немного погуглил (находя эту тему). После 5 минут попыток и ошибок я обнаружил, что вы можете просто использовать «И», чтобы вернуть две (возможно, больше - еще не проверенные) в одной строке возврата.

Мой код:

  function get_id(){
    global $b_id, $f_id;
    // stuff happens
    return $b_id AND $f_id;
  }
  //later in the code:
  get_id();
  var_dump($b_id);
  var_dump($f_id); // tested output by var_dump

оно работает. Я получил оба значения, которые я ожидал получить / должен получить. Я надеюсь, что смогу помочь любому, читающему эту ветку :)


3
Это не правильно. «И» - это просто логический оператор, поэтому ваша функция фактически возвращает единственное логическое значение. Единственная причина, по которой он работает, это то, что вы объявляете $ b_id и $ f_id глобальными переменными. Удалите «И», а также оператор возврата в целом, и вы увидите, что ваши результаты остаются прежними.
Мэтт Стайлс

это очень вводит в заблуждение, так как вы объявили $ b_id и $ f_id глобальными, поэтому доступны из любого контекста.
Паулюс
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.