Функция объединения для PHP?

131

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

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

Mikl
источник
11
По теме: новый оператор объединения с нулевым значением?? для PHP 7.
kojiro 01
Более подробную информацию об операторе слияния с нулевым значением можно найти здесь - stackoverflow.com/questions/33666256/…
Питер,
1
Отметим, что PHP7 реализовал эту функцию
Гжегож
@Grzegorz: Оператор - это не функция, или где вы нашли эту функцию, новую в PHP 7;)
hakre
Под функцией я не имел в виду функцию;) Особенность. Я не был точен. Спасибо :)
Grzegorz

Ответы:

194

В 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

Kevin
источник
25
А как насчет нескольких троичных ярлыков, может быть что-то вроде "echo $ a?: $ B?: $ C?: $ D;" работай?
ChrisR
5
Не работает должным образом для массивов. Например, при попытке проверить, является ли неопределенный элемент массива ложным, это приведет к ошибке. $input['properties']['range_low'] ?: '?'
Keyo
5
Вы должны получить уведомление о неопределенном индексе независимо от использования оператора объединения.
Кевин
2
Несколько ложных аргументов возвращают последний аргумент, array() ?: null ?: falseвозвращается false. Оператор действительно вменяемый.
Брэд Кох
6
Имейте в виду, что это не просто принимает ненулевое значение, как coalesce в других языках, но любое значение, которое будет неявно преобразовано в логическое значение. Так что не забудьте освежить свои правила приведения типов
DanMan
65

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

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

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

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

Флори
источник
Наконец, повсюду больше нет isset () и empty ()!
Джордж Каган
7
@timeNomad, который вам все еще понадобится, пуст, он проверяет только null
Набил Хан,
Единственный способ добиться безопасного «ложного слияния» - это использовать их по чуть-чуть:($_GET['doesNotExist'] ?? null) ?: 'fallback'
Натан Баулч
Однако преимущество ?:over ??состоит в том, что он также объединяет пустые значения, чего ??не происходит. Подобно поведению логического оператора ИЛИ в JavaScript (то есть $val || 'default'), я нашел бы ?:быть более практичной формой сливающимся , если в нашей практике мы в конечном итоге найти себя обработку как пустые и нуль таким же образом (то есть $val ?: 'default'). И если вы хотите продвинуть проблему дальше и проглотить E_NOTICE, вы можете даже возразить:echo @$val ?: 'default';
Мэтт Борха,
29

Первое обращение по запросу "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

Будет бритва
источник
9
Сохраните крошечный бит оперативной памяти и не дублируйте аргументы в массиве, просто выполните foreach (func_get_args () as $ arg) {}
TravisO
17
@ [Альфред, Кьяран] - вы не правы. foreach () оценивает первый аргумент только один раз, чтобы получить массив, а затем выполняет итерацию по нему.
gahooa
6
Помещение func_get_args () внутри foreach (здесь как $ arg) ничего не изменит с точки зрения производительности.
Savageman
7
@Savageman ... точно ... если вы думаете о том, чтобы выжать из своего приложения эту миллисекунду производительности или несколько байтов памяти, вы, вероятно, столкнетесь с неправильным узким местом производительности / памяти
ChrisR
4
По иронии судьбы, теперь это первый успех "php coalesce" в Google.
Уилл Шейвер
18

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

function coalesce() {
  return array_shift(array_filter(func_get_args()));
}
Итан Кент
источник
1
это «правдивое» объединение, использующее array_filter, чтобы избавиться от всего, что оценивается как false (включая null) в n аргументах, переданных. Я предполагаю, что использование shift вместо первого элемента в массиве как-то более надежно, но это часть я не знаю. см .: php.net/manual/en/…
Адам Толли
3
Мне это нравится, но я должен согласиться с @hakre - coalesceон должен возвращать первый ненулевой аргумент, с которым он сталкивается, который будет включать FALSE. Однако эта функция отбросит FALSE, вероятно, не то, что op имеет в виду (по крайней мере, не то, что я хотел бы от coalesceфункции).
Madbreaks
1
По ссылке следует передавать только переменные
Бен Синклер,
9

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

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

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

Андрей
источник
В этом случае очень хорошо работают объединения массивов ( $getstuff = $_GET+$_SESSION+array('id'=>null);$id=$getstuff['id'];).
Brilliand
@Quill, что это должно значить? Вы предложили решение со ссылкой?
Бен Синклер,
PHP 7 представляет новый прекрасный тернарный оператор isset,?? чтобы сделать эту очень распространенную операцию более краткой.
Botimer
6

Убедитесь, что вы точно определили, как эта функция должна работать с определенными типами. В 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 () возвращает только 2 из них.

Питер Бейли
источник
2

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

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

ой

Чтобы преодолеть это, требуется второй аргумент и определение функции. Вызываемая функция отвечает за сообщение 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, но не повезло.

Madbreaks
источник
0

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

function coalesce() {
  $args = func_get_args();
  foreach ($args as $arg) {
    if (!empty($arg)) {
    return $arg;
    }
  }
  return $args[0];
}
Mikl
источник
0

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

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

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

Пауло Фрейтас
источник
По ссылке следует передавать только переменные,
Бен Синклер,
Ага, я нарушил строгие правила демонстрации, просто чтобы было проще. :)
Пауло Фрейтас