Многие языки программирования имеют функцию объединения (возвращает первое значение, отличное от NULL, пример). К сожалению, в 2009 году PHP этого не сделал.

Что было бы хорошим способом реализовать его в PHP, пока сам PHP не получит функцию объединения?

133
mikl 18 Июн 2009 в 19:49

9 ответов

Лучший ответ

В php 5.3 есть новый оператор, который делает это: ?:

// A
echo 'A' ?: 'B';

// B
echo '' ?: 'B';

// B
echo false ?: 'B';

// B
echo null ?: 'B';

Источник: http://www.php.net/ChangeLog-5.php#5.3 .0

196
Kevin 12 Дек 2009 в 01:32

В PHP 7 появился настоящий оператор объединения:

echo $_GET['doesNotExist'] ?? 'fallback'; // prints 'fallback'

Если значение до ?? не существует или является null значением после ??.

Усовершенствованием по сравнению с упомянутым оператором ?: является то, что ?? также обрабатывает неопределенные переменные, не бросая E_NOTICE.

68
flori 28 Ноя 2015 в 20:15

Первое обращение по запросу "php coalesce" в Google.

function coalesce() {
  $args = func_get_args();
  foreach ($args as $arg) {
    if (!empty($arg)) {
      return $arg;
    }
  }
  return NULL;
}

http://drupial.com/content/php-coalesce

29
Will Shaver 18 Июн 2009 в 15:51

Мне очень нравится оператор? :. К сожалению, это еще не реализовано в моей производственной среде. Поэтому я использую эквивалент этого:

function coalesce() {
  return array_shift(array_filter(func_get_args()));
}
18
Ethan Kent 14 Янв 2011 в 04:58

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

$id = coalesce($_GET['id'], $_SESSION['id'], null);

Но в большинстве случаев это приведет к ошибке PHP с E_NOTICE. Единственный безопасный способ проверить существование переменной перед ее использованием - использовать ее непосредственно в empty () или isset (). Тернарный оператор, предложенный Кевином, - лучший вариант, если вы знаете, что все параметры в вашем объединении, как известно, инициализированы.

10
Brad Koch 9 Апр 2013 в 15:14

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

function coalesce() {
  $args = func_get_args();
  foreach ($args as $arg) {
    if (!empty($arg)) {
    return $arg;
    }
  }
  return $args[0];
}
0
mikl 18 Июн 2009 в 15:54

PHP 5.3+, с закрытием:

function coalesce()
{
    return array_shift(array_filter(func_get_args(), function ($value) {
        return !is_null($value);
    }));
}

Демо: https://eval.in/187365

0
Paulo Freitas 2 Сен 2014 в 20:21

Убедитесь, что вы точно определили, как эта функция должна работать с определенными типами. В PHP есть множество функций проверки типов или похожих функций, поэтому убедитесь, что вы знаете, как они работают. Это пример сравнения is_null () и empty ()

$testData = array(
  'FALSE'   => FALSE
  ,'0'      => 0
  ,'"0"'    => "0"  
  ,'NULL'   => NULL
  ,'array()'=> array()
  ,'new stdClass()' => new stdClass()
  ,'$undef' => $undef
);

foreach ( $testData as $key => $var )
{
  echo "$key " . (( empty( $var ) ) ? 'is' : 'is not') . " empty<br>";
  echo "$key " . (( is_null( $var ) ) ? 'is' : 'is not')  . " null<br>";
  echo '<hr>';
}

Как видите, empty () возвращает true для всех из них, но is_null () возвращает только два из них.

6
Peter Bailey 18 Июн 2009 в 16:43

Я расширяю ответ, опубликованный Итаном Кентом. В этом ответе будут отброшены ненулевые аргументы, которые оцениваются как false из-за внутренней работы array_filter, чего обычно не делает функция coalesce. Например:

echo 42 === coalesce(null, 0, 42) ? 'Oops' : 'Hooray';

ой

Чтобы преодолеть это, требуется второй аргумент и определение функции. Функция callable отвечает за сообщение array_filter, следует ли добавлять текущее значение массива в массив результатов:

// "callable"
function not_null($i){
    return !is_null($i);  // strictly non-null, 'isset' possibly not as much
}

function coalesce(){
    // pass callable to array_filter
    return array_shift(array_filter(func_get_args(), 'not_null'));
}

Было бы неплохо, если бы вы могли просто передать isset или 'isset' в качестве второго аргумента для array_filter, но не тут-то было.

2
hakre 22 Апр 2018 в 11:23