Лучший способ присвоить переменной значение по умолчанию (имитировать Perl ||, || =)


134

Я люблю делать такие вещи в Perl: $foo = $bar || $bazназначить $bazв $fooслучае $barпустой или не определено. У вас также есть , $foo ||= $bletchкоторые будут назначать только $bletchв $fooслучае $fooне определен или пустой.

Тройной оператор в этой ситуации утомителен и утомителен. Конечно, есть простой, элегантный метод, доступный в PHP?

Или единственный ответ - пользовательская функция, которая использует isset ()?



1
Кстати, операторы Perl с желаемым функционалом есть //и //=существуют с Perl v5.10.0. Оригинал ||и ||=тест на логическое значение, а не на определенность.
Палек

@Palec, почему 4-летний вопрос с 29 ответами должен быть идентифицирован как дубликат 1-летнего вопроса с 6 ответами (который сам был помечен как дубликат другого вопроса?) Я думаю, что есть большая ценность в сохранении этого вопрос, так как заголовок более общий (не ссылается на ответ, т.е. isset ()).
Том Оджер

Они четкие и точные дубликаты. Следует признать, что я не особо задумывался о том, какой из них должен быть оригиналом, я занимался чем-то другим, и целью была связь между ними. Убираю мой VTC.
Палек,

Точная копия, помеченная (IMO по ошибке) дубликатом другого вопроса: сокращение от PHP для isset ()?
Палек

Ответы:


131

В PHP 7 у нас наконец есть способ сделать это элегантно. Это называется нулевым оператором слияния . Вы можете использовать это так:

$name = $_GET['name'] ?? 'john doe';

Это эквивалентно

$name = isset($_GET['name']) ? $_GET['name']:'john doe';

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

3
Я думал, что Мариано тянет нас за ноги, но нет, это вещь <=>и довольно точная!
HPWD

1
Обратите внимание, что оператор слияния null ведет себя не так, как условный оператор, так как он специфичен для nullзначения. Например, если $_GET['name']задана пустая строка, первая строка будет возвращать пустую строку, но мы можем вернуть «Джон Доу», используя $_GET['name'] ? $_GET['name'] : 'john doe'.
VPhantom

211

В PHP 5.3 есть сокращенный ?:оператор:

$foo = $bar ?: $baz;

Который присваивает, $barесли это не пустое значение (я не знаю, как это будет отличаться в PHP от Perl), в противном случае $baz, и такое же, как в Perl и более старых версиях PHP:

$foo = $bar ? $bar : $baz;

Но PHP не имеет составного оператора присваивания для этого (то есть, нет эквивалента Perl ||=).

Кроме того, PHP будет шуметь, если $barне установлен, если вы не отключите уведомления. Существует также семантическая разница между isset()и empty(). Первый возвращает false, если переменная не существует или имеет значение NULL. Последние возвращает истину , если она не существует, или имеет значения 0, '', falseили NULL.


2
+1 Для ознакомления с еще одной замечательной функцией 5.3, которую я пропускаю на своих серверах RHEL5 / PHP5.1.2.
Майкл Берковски

Я предполагаю, что вы имеете в виду, The first returnsа не The secondв вашем предпоследнем предложении.
Тото

21
Обратите внимание, что если ваша переменная не определена, PHP выдаст уведомление об этом. Это, к сожалению, не является заменой. $var = isset($var) ? $var : 'default value'; Он говорит, что в ответе ... просто указывает на это снова для тех, кто просматривает его. :-D
Брэд

6
Это плохо делать $ var = @ $ var?: 'Default value'; Если так, то почему? Учитывая, что единственная «ошибка» может заключаться в том, что $ var не установлен, и что нам все равно, если $ var не установлен ...
Codemonkey

8

Спасибо за все отличные ответы!

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

function set_if_defined(&$var, $test){
    if (isset($test)){
        $var = $test;
        return true;
    } else {
        return false;
    }
}

function set_unless_defined(&$var, $default_var){
    if (! isset($var)){
        $var = $default_var;
        return true;
    } else {
        return false;
    }
}

function select_defined(){
    $l = func_num_args();
    $a = func_get_args();
    for ($i=0; $i<$l; $i++){
        if ($a[$i]) return $a[$i];
    }
}

Примеры:

// $foo ||= $bar;
set_unless_defined($foo, $bar);

//$foo = $baz || $bletch
$foo = select_defined($baz, $bletch);

Я уверен, что это можно улучшить.


7

Распространенная идиома для совместимости со старыми версиями PHP:

 $var = $bool   or   $var = "default";
 // If I use it, then only with excessive spaces for clarity.

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


Не отправлено ли уведомление, $bool ? $bool : "default"если $boolоно не определено?
BoltClock

Конечно, это то же самое. Я предположил, что OP имеет в виду isset($var) ? $var : DEFAULT. Но звучит так, будто он все равно хочет их избегать.
Марио

6

В PHP ранее, чем 7. *, можно использовать?: Для неопределенной переменной, ошибки которой локально подавляются с помощью @:

$foo = @$bar ?: $baz;

0

это еще один хороший формат для issetдела

isset($foo) || $foo= $bar;

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

$foo = (isset($oData['foo']))?$bar['foo']:'default value';


0

Возможное решение: defaultFor ()

Если у нас нет заводского решения (которое действительно очень раздражает), я бы порекомендовал следующего маленького помощника. Это делает работу в большинстве случаев:


    function defaultFor(&$x,$default=null) {
        if(!isset($x)) $x = $default;
    }

    //--------------------  Now you can do this: --------------

    defaultFor($a,"Jack");  // if $a is not set, it will be "Jack"
    defaultFor($x);         // no more notices for $x but keep it !isset

Я надеюсь, что это близко к тому, что вы хотели достичь. Он не выдаст вам никаких уведомлений, если вы используете его с несуществующей переменной, и это довольно удобно. Конечно, у него есть недостаток: значение по умолчанию всегда вычисляется заранее, поэтому не используйте его с чем-то тяжелым в качестве второго параметра, например, file_get_contents или чем-то еще. В этих случаях вам лучше с isseting.


0

Я думаю, что в целом делать что-то вроде этого:

$foo = $bar || $baz;

плохая идея, если только $barи $bazоба не являются булевыми. Если они не:

$bar = 10;
$baz = 11;

тогда возникает вопрос: что определяет, является ли что-то истинным или ложным? Большинство людей, вероятно, ожидают, что ноль будет ложным, а все остальное - правдой. Но с некоторыми языками (например, Ruby) только falseи nilявляются ложными, что означает и то 0и другое 1. Из-за этой межъязыковой неоднозначности, я думаю, что лучше всего быть точным в следующих случаях:

if ($bar !== 0) {
   $foo = $bar;
} else {
   $foo = $baz;
}

или:

$foo = $bar !== 0 ? $bar : $baz;
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.