PHP-тернарный оператор против оператора нулевой коалесценции

Может ли кто-нибудь объяснить различия между сокращением тернарных операторов (?:) и нулевым коалесцирующим оператором (??) в PHP?

Когда они ведут себя по-разному и когда одинаково (если это происходит)?

$a ?: $b

VS.

$a ?? $b

Ответы

Ответ 1

Когда ваш первый аргумент равен нулю, они в основном одинаковы, за исключением того, что объединение с нулем не будет выводить E_NOTICE, когда у вас есть неопределенная переменная. Документация по миграции на PHP 7.0 содержит следующее:

Нулевой оператор объединения (??) был добавлен как синтаксический сахар для общего случая необходимости использовать троичный в сочетании с Исеть(). Возвращает свой первый операнд, если он существует и не равен NULL; в противном случае возвращается второй операнд.

Вот пример кода, чтобы продемонстрировать это:

<?php

$a = null;

print $a ?? 'b'; // b
print "\n";

print $a ?: 'b'; // b
print "\n";

print $c ?? 'a'; // a
print "\n";

print $c ?: 'a'; // Notice: Undefined variable: c in /in/apAIb on line 14
print "\n";

$b = array('a' => null);

print $b['a'] ?? 'd'; // d
print "\n";

print $b['a'] ?: 'd'; // d
print "\n";

print $b['c'] ?? 'e'; // e
print "\n";

print $b['c'] ?: 'e'; // Notice: Undefined index: c in /in/apAIb on line 33
print "\n";

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

Выполните код: https://3v4l.org/McavC

Конечно, это всегда предполагает, что первый аргумент - null. Как только он перестанет иметь значение null, вы получите различия в том, что оператор ?? всегда будет возвращать первый аргумент, а сокращение ?: будет только в том случае, если первый аргумент верен, и это зависит от того, как PHP будет приведение типов к логическому значению.

Итак:

$a = false ?? 'f'; // false
$b = false ?: 'g'; // 'g'

тогда будет иметь $a равным false и $b равному 'g'.

Ответ 2

Если вы используете так называемый кратковременный оператор, это вызовет уведомление, если $_GET['username'] не установлено:

$val = $_GET['username'] ?: 'default';

Итак, вы должны сделать что-то вроде этого:

$val = isset($_GET['username']) ? $_GET['username'] : 'default';

Оператор нулевой коалесценции эквивалентен приведенному выше оператору и будет возвращать значение по умолчанию, если $_GET['username'] не задано или null:

$val = $_GET['username'] ?? 'default';

Обратите внимание, что он не проверяет правду. Он проверяет только если он установлен и не равен нулю.

Вы также можете сделать это, и будет возвращено первое определенное (set, not null) значение:

$val = $input1 ?? $input2 ?? $input3 ?? 'default';

Теперь это правильный коалесцирующий оператор.

Ответ 3

Основное различие заключается в том, что

  1. Терминальное выражение оператора expr1?: expr3 возвращает expr1 если expr1 значение TRUE но, с другой стороны, выражение Null Coalescing Operator (expr1)?? (expr2) (expr1)?? (expr2) вычисляет expr1 если expr1 не является NULL

  2. Терминальный оператор expr1?: expr3 испускает уведомление, если значение левой стороны (expr1) не существует, а с другой стороны Null Coalescing Operator (expr1)?? (expr2) (expr1)?? (expr2) В частности, не выделяет уведомление, если значение левой стороны (expr1) не существует, как isset().

  3. ТернарОператор оставлен ассоциативным

    ((true ? 'true' : false) ? 't' : 'f');
    

    Оператор Null Coalescing является правильным ассоциативным

    ($a ?? ($b ?? $c));
    

Теперь давайте объясним разницу между примером:

Тернарный оператор (?:)

$x='';
$value=($x)?:'default';
var_dump($value);

// The above is identical to this if/else statement
if($x){
  $value=$x;
}
else{
  $value='default';
}
var_dump($value);

Оператор Null Coalescing (??)

$value=($x)??'default';
var_dump($value);

// The above is identical to this if/else statement
if(isset($x)){
  $value=$x;
}
else{
  $value='default';
}
var_dump($value);

Вот таблица, объясняющая разницу и сходство между '??' и ?:

enter image description here

Специальное примечание. Оператор коалесценции и тернарный оператор являются выражением и что он не оценивает переменную, а результат выражения. Это важно знать, хотите ли вы вернуть переменную по ссылке. Утверждение возвращает $ foo?? $ Бар; и вернуть $ var == 42? $ a: $ b; в функции возврата-ссылки не будет работать и выдается предупреждение.

Ответ 4

Запустите ниже в интерактивном режиме php -a (php -a на терминале). Комментарий к каждой строке показывает результат.

var_dump (false ?? 'value2');   # bool(false)
var_dump (true  ?? 'value2');   # bool(true)
var_dump (null  ?? 'value2');   # string(6) "value2"
var_dump (''    ?? 'value2');   # string(0) ""
var_dump (0     ?? 'value2');   # int(0)

var_dump (false ?: 'value2');   # string(6) "value2"
var_dump (true  ?: 'value2');   # bool(true)
var_dump (null  ?: 'value2');   # string(6) "value2"
var_dump (''    ?: 'value2');   # string(6) "value2"
var_dump (0     ?: 'value2');   # string(6) "value2"

Итак, это моя интерпретация:

1. Оператор Null Coalescing - ?? :

  • ?? как "ворота", который пропускает только NULL.
  • Таким образом, он всегда возвращает первый параметр, если первый параметр не имеет значения NULL.
  • Это означает ?? такое же, как ( !isset() || is_null() )

2. Тернарный оператор - ?:

  • ?: как ворота, которые пропускают anything falsy - включая NULL
  • 0, empty string, NULL, false !isset(), empty().. все, что пахнет ложью
  • Как и классический тернарный оператор: echo ($x? $x: false)
  • ПРИМЕЧАНИЕ: ?: Выдает PHP NOTICE на неопределенные (unset или !isset()) переменные

3. Итак, доктор, когда я использую ?? и ?:..

  • Я просто шучу - я не доктор, и это всего лишь интерпретация
  • Я бы использовал ?: Когда
    • выполнение empty($x) проверок
    • Классическая тройная операция типа !empty($x)? $x: $y !empty($x)? $x: $y можно сократить до $x?: $y
    • if(!$x) { fn($x); } else { fn($y); } if(!$x) { fn($x); } else { fn($y); } можно укоротить до fn(($x?: $y))
  • Я бы использовал ?? когда
    • Я хочу сделать !isset() || is_null() !isset() || is_null()
    • например, проверить, существует ли объект - $object = $object?? new objClassName(); $object = $object?? new objClassName();

4. Операторы стекирования...

  1. Тернарный оператор может быть уложен в стопку...

    echo 0 ?: 1 ?: 2 ?: 3; //1
    echo 1 ?: 0 ?: 3 ?: 2; //1
    echo 2 ?: 1 ?: 0 ?: 3; //2
    echo 3 ?: 2 ?: 1 ?: 0; //3
    
    echo 0 ?: 1 ?: 2 ?: 3; //1
    echo 0 ?: 0 ?: 2 ?: 3; //2
    echo 0 ?: 0 ?: 0 ?: 3; //3
    

    Источник и кредит для этого кода

    Это в основном последовательность:

    if( truthy ) {}
    else if(truthy ) {}
    else if(truthy ) {}
    ..
    else {}
    
  2. Оператор Null Coalese может быть уложен...

    $v = $x ?? $y ?? $z; 
    

    Это последовательность:

    if(!isset($x) || is_null($x) ) {} 
    else if(!isset($y) || is_null($y) ) {}
    else {}
    
  3. Используя укладку, я могу сократить это:

    if(!isset($_GET['name'])){
       if(isset($user_name) && !empty($user_name)){
          $name = $user_name;
       }else {
          $name = 'anonymous';
       }
    } else { 
       $name = $_GET['name'];
    }
    

    К этому:

    $name = $_GET['name'] ?? $user_name ?: 'anonymous';
    

    Круто, правда? :-)

Ответ 5

Оба они ведут себя по-разному, когда речь заходит о динамической обработке данных.

Если переменная пуста (''), нулевое коалесцирование будет обрабатывать переменную как true, но сокращенный тернарный оператор не будет. И это что-то иметь в виду.

$a = NULL;
$c = '';

print $a ?? '1b';
print "\n";

print $a ?: '2b';
print "\n";

print $c ?? '1d';
print "\n";

print $c ?: '2d';
print "\n";

print $e ?? '1f';
print "\n";

print $e ?: '2f';

И вывод:

1b
2b

2d
1f

Notice: Undefined variable: e in /in/ZBAa1 on line 21
2f

Ссылка: https://3v4l.org/ZBAa1

Ответ 6

Оба являются сокращениями для более длинных выражений.

?: коротка для $a? $a: $b $a? $a: $b. Это выражение будет иметь значение $ a, если $ a равно TRUE.

?? сокращение от isset($a)? $a: $b isset($a)? $a: $b. Это выражение будет иметь значение $ a, если $ a установлено и не равно нулю.

Их варианты использования перекрываются, когда $ a не определено или равно нулю. Когда $ a не определено ?? не будет выдавать E_NOTICE, но результаты будут такими же. Когда $ a равно нулю, результат тот же.

Ответ 7

Для начинающих:

Нулевой оператор объединения (??)

Все верно, кроме null значений и неопределенных (переменная/индекс массива/атрибуты объекта)

например:

$array = [];
$object = new stdClass();

var_export (false ?? 'second');                           # false
var_export (true  ?? 'second');                           # true
var_export (null  ?? 'second');                           # 'second'
var_export (''    ?? 'second');                           # ""
var_export ('some text'    ?? 'second');                  # "some text"
var_export (0     ?? 'second');                           # 0
var_export ($undefinedVarible ?? 'second');               # "second"
var_export ($array['undefined_index'] ?? 'second');       # "second"
var_export ($object->undefinedAttribute ?? 'second');     # "second"

это в основном проверка того, что переменная (индекс массива, атрибут объекта и т.д.) существует и не равна null. аналогично функции isset

Сокращенное обозначение троичного оператора (? :)

каждое ложное (false, null, 0, пустая строка) принимается за false, но если оно не определено, оно также принимается за false, но Notice выдаст

бывший

$array = [];
$object = new stdClass();

var_export (false ?: 'second');                           # "second"
var_export (true  ?: 'second');                           # true
var_export (null  ?: 'second');                           # "second"
var_export (''    ?: 'second');                           # "second"
var_export ('some text'    ?? 'second');                  # "some text"
var_export (0     ?: 'second');                           # "second"
var_export ($undefinedVarible ?: 'second');               # "second" Notice: Undefined variable: ..
var_export ($array['undefined_index'] ?: 'second');       # "second" Notice: Undefined index: ..
var_export ($object->undefinedAttribute ?: 'second');     # "Notice: Undefined index: ..

Надеюсь это поможет

Ответ 8

Прокрутите вниз по эту ссылку и просмотрите раздел, это дает сравнительный пример, как показано ниже:

<?php
/** Fetches the value of $_GET['user'] and returns 'nobody' if it does not exist. **/
$username = $_GET['user'] ?? 'nobody';
/** This is equivalent to: **/
$username = isset($_GET['user']) ? $_GET['user'] : 'nobody';

/** Coalescing can be chained: this will return the first defined value out of $_GET['user'], $_POST['user'], and 'nobody'. **/
$username = $_GET['user'] ?? $_POST['user'] ?? 'nobody';
?>

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

Нулевой коалесцирующий оператор (??) был добавлен в качестве синтаксического сахара для общего случая использования тройной связи в сочетании с isset(). Он возвращает свой первый операнд, если он существует, и не является NULL; в противном случае он возвращает свой второй операнд.

По сути, использование коалесцирующего оператора сделает его автоматической проверкой на значение null в отличие от тернарного оператора.

Ответ 9

Кажется, есть плюсы и минусы использования ?? или ?:. Про использование ?: заключается в том, что он оценивает значение false и null и "" то же самое. Кон является то, что он сообщает E_NOTICE, если предыдущий аргумент равен null. С ?? pro - это отсутствие E_NOTICE, но con - это то, что он не оценивает значение false и null. По моему опыту, я видел, что люди начинают использовать нулевые и ложные взаимозаменяемые, но затем они в конечном итоге прибегают к модификации своего кода, чтобы быть совместимыми с использованием либо нулевого, либо ложного, но не того и другого. Альтернативой является создание более сложного тернарного состояния: (isset($something) or !$something) ? $something : $something_else.

Ниже приведен пример различия в использовании оператора ?? с использованием как null, так и false:

$false = null;
$var = $false ?? "true";
echo $var . "---<br>";//returns: true---

$false = false;
$var = $false ?? "true";
echo $var . "---<br>"; //returns: ---

Однако, разрабатывая троичный оператор, мы можем сделать ложную или пустую строку "", как если бы это был нуль, не выбрасывая e_notice:

$false = null;
$var = (isset($false) or !$false) ? $false : "true";
echo $var . "---<br>";//returns: ---

$false = false;
$var = (isset($false) or !$false) ? $false : "true";
echo $var . "---<br>";//returns: ---

$false = "";
$var = (isset($false) or !$false) ? $false : "true";
echo $var . "---<br>";//returns: ---

$false = true;
$var = (isset($false) or !$false) ? $false : "true";
echo $var . "---<br>";//returns: 1---

Лично я считаю, что было бы очень хорошо, если бы в будущем rev PHP включался другой новый оператор: :?, который заменил вышеупомянутый синтаксис. то есть: // $var = $false :? "true"; Этот синтаксис будет одинаково оценивать значение null, false и "" и не вызывать E_NOTICE...

Ответ 10

class a
{
    public $a = 'aaa';
}

$a = new a();

echo $a->a;  // Writes 'aaa'
echo $a->b;  // Notice: Undefined property: a::$b

echo $a->a ?? '$a->a does not exists';  // Writes 'aaa'

// Does not throw an error although $a->b does not exist.
echo $a->b ?? '$a->b does not exist.';  // Writes $a->b does not exist.

// Does not throw an error although $a->b and also $a->b->c does not exist.
echo $a->b->c ?? '$a->b->c does not exist.';  // Writes $a->b->c does not exist.

Ответ 11

Другие ответы идут глубоко и дают большие объяснения. Для тех, кто ищет быстрый ответ,

$a ?: 'fallback' - это $a ? $a : 'fallback'

в то время как

$a ?? 'fallback' - это $a = isset($a) ? $a : 'fallback'


Основное отличие будет в том случае, если левый оператор либо:

  • Ложное значение, которое НЕ является нулевым (0, '', false, [],...)
  • Неопределенная переменная

Ответ 12

Null Coalescing operator выполняет только две задачи: он проверяет whether the variable is set и whether it is null. Взгляните на следующий пример:

<?php
# case 1:
$greeting = 'Hola';
echo $greeting ?? 'Hi There'; # outputs: 'Hola'

# case 2:
$greeting = null;
echo $greeting ?? 'Hi There'; # outputs: 'Hi There'

# case 3:
unset($greeting);
echo $greeting ?? 'Hi There'; # outputs: 'Hi There'

В приведенном выше примере кода указано, что Null Coalescing operator обрабатывает несуществующую переменную и переменную, которая установлена ​​на NULL таким же образом.

Null Coalescing operator является улучшением по сравнению с ternary operator. Посмотрите на следующий фрагмент кода, сравнивающий два:

<?php /* example: checking for the $_POST field that goes by the name of 'fullname'*/
# in ternary operator
echo "Welcome ", (isset($_POST['fullname']) && !is_null($_POST['fullname']) ? $_POST['fullname'] : 'Mr. Whosoever.'); # outputs: Welcome Mr. Whosoever.
# in null coalecing operator
echo "Welcome ", ($_POST['fullname'] ?? 'Mr. Whosoever.'); # outputs: Welcome Mr. Whosoever.

Таким образом, разница между ними заключается в том, что оператор Null Coalescing operator предназначен для обработки переменных undefined лучше, чем ternary operator. В то время как ternary operator является сокращением для if-else.

Null Coalescing operator не предназначен для замены ternary operator, но в некоторых случаях использования, как в приведенном выше примере, он позволяет писать чистый код с меньшими проблемами.

Кредиты: http://dwellupper.io/post/6/php7-null-coalescing-operator-usage-and-examples

Ответ 13

При использовании суперглобальных переменных, таких как $ _GET или $ _REQUEST, вы должны знать, что они могут быть пустой строкой. В этом конкретном случае этот пример

$username = $_GET['user'] ?? 'nobody';

потерпит неудачу, потому что значение $ username теперь является пустой строкой.

Поэтому при использовании $ _GET или даже $ _REQUEST вы должны использовать вместо этого троичный оператор, например:

$username = (!empty($_GET['user'])?$_GET['user']:'nobody';

Теперь значение $ username равно "nobody", как и ожидалось.