Кілька повернень від функції


198

Чи можлива функція з двома поверненнями на зразок цього:

function test($testvar)
{
  // Do something

  return $var1;
  return $var2;
}

Якщо так, то як я можу отримати кожне повернення окремо?


1
Що саме ви намагаєтеся досягти? Звичайно, якщо ви пояснили свою справжню проблему, хтось тут може допомогти вам досягти елегантного рішення.
Майк Даніельс

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

5
Якщо вам потрібні обидва значення, поверніть їх у масив.
Bhargav Nanekalva

2
@DragonLord в PHP 7.1 ви можете використовувати синтаксис короткого списку
Janus Troelsen

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 мав Перлаwantarray()
Марк Б

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);
Тім Купер

@Tim Cooper: 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

Деструкція - це дуже потужний інструмент. Він також може знищити пари key => пар значень:

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

Погляньте на нову сторінку функцій для PHP 7.1:

Нові можливості


5
Я хотів би, щоб StackOverflow мав таку функцію, як "Featured answer", навіть коли вона не прийнята до моменту створення питання, оскільки ця відповідь тут є досить корисною та оновленою, але це, поза темою, звичайно.
CD

3
@JonatasCD - не впевнений, чому ти кажеш, що ця відповідь є "поза темою". У PHP 7.1 це є найбільш зручним способом для створення і обробок кілька значень, що повертаються з функції. Так що для нових версій php це чудова відповідь на оригінально прийняту відповідь.
ToolmakerSteve

@ToolmakerSteve Я думаю, ти мене зрозумів неправильно. "Поза темою" до питання було моєю пропозицією мати можливість змінити те, що було прийнято, спираючись на майбутні реалізації. Це було нічого проти вашої відповіді;)
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

Неможливо мати дві заяви про повернення. Однак вона не кидає помилки, але при виклику функції ви отримаєте лише перше значення повернення оператора. Ми можемо використовувати return масив, щоб отримати кілька значень взамін. Наприклад:

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

Повторно "отримайте значення двох або більше змінних" : Ви маєте на увазі "повернення значень двох або більше змінних" ?
Пітер Мортенсен

0

PHP все ще використовує "параметри"? Якщо так, ви можете використовувати синтаксис для зміни одного або декількох параметрів, що надходять у вашу функцію. Тоді ви зможете використовувати змінену змінну після повернення функції.


-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
Це неправильно. 'AND' - це просто булевий оператор, тому ваша функція фактично повертає єдине булеве значення. Єдиною причиною, що, здається, працює, є те, що ви оголошуєте $ b_id та $ f_id глобальними змінними. Видаліть "І", а також заяву про повернення взагалі, і ви побачите, що ваші результати залишаються тими ж.
Метт Стайлз

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