Может ли кто-нибудь объяснить разницу между троичным оператором стенографией (?:
) и нулевой оператор объединения (??
) в PHP?
Когда они ведут себя по-разному и когда одинаково (если это вообще происходит)?
$a ?: $b
VS.
$a ?? $b
Когда ваш первый аргумент равен нулю, они в основном совпадают, за исключением того, что объединение с нулем не будет выводить E_NOTICE
когда у вас есть неопределенная переменная. Документация по миграции на PHP 7.0 имеет это сказать:
Нулевой оператор объединения (??) был добавлен как синтаксический сахар
для общего случая необходимости использовать троичный в сочетании с
Исеть (). Возвращает свой первый операнд, если он существует и не равен NULL;
в противном случае он возвращает свой второй операнд.
Вот пример кода, чтобы продемонстрировать это:
<?php
$a = null;
print $a ?? 'b';
print "\n";
print $a ?: 'b';
print "\n";
print $c ?? 'a';
print "\n";
print $c ?: 'a';
print "\n";
$b = array('a' => null);
print $b['a'] ?? 'd';
print "\n";
print $b['a'] ?: 'd';
print "\n";
print $b['c'] ?? 'e';
print "\n";
print $b['c'] ?: 'e';
print "\n";
И это вывод:
b
b
a
Notice: Undefined variable: c in /in/apAIb on line 14
a
d
d
e
Notice: Undefined index: c in /in/apAIb on line 33
e
Линии, которые имеют уведомление, являются теми, где я использую сокращенный тернарный оператор, а не оператор объединения нулей. Тем не менее, даже с уведомлением, PHP даст тот же ответ обратно.
Выполнить код: https://3v4l.org/McavC
Конечно, это всегда предполагает, что первый аргумент null
, Как только он перестанет быть нулевым, вы получите различия в том, что ??
Оператор всегда будет возвращать первый аргумент, в то время как ?:
сокращение было бы только в том случае, если первый аргумент был правдивым, и это зависит от того, как PHP будет приводить вещи к булевому типу.
Так:
$a = false ?? 'f';
$b = false ?: 'g';
будет иметь $a
быть равным false
а также $b
равно 'g'
,
Если вы используете ярлык троичного оператора, как это, это вызовет уведомление, если $_GET['username']
не установлено:
$val = $_GET['username'] ?: 'default';
Поэтому вместо этого вы должны сделать что-то вроде этого:
$val = isset($_GET['username']) ? $_GET['username'] : 'default';
нулевой оператор объединения эквивалентно приведенному выше утверждению и вернет значение «по умолчанию», если $_GET['username']
не установлен или null
:
$val = $_GET['username'] ?? 'default';
Обратите внимание, что это не проверяет правдивость. Он проверяет, только если он установлен, а не ноль.
Вы также можете сделать это, и первый определенный (установить и не null
) значение будет возвращено:
$val = $input1 ?? $input2 ?? $input3 ?? 'default';
Теперь это правильный оператор объединения.
Основное отличие состоит в том, что
Троичный оператор выражение expr1 ?: expr3
возвращается expr1
если expr1
оценивает
TRUE
но с другой стороны Нулевой оператор объединения выражение (expr1) ?? (expr2)
оценивает expr1
если expr1
является не NULL
троичный
оператор expr1 ?: expr3
подать уведомление, если левая сторона
значение (expr1)
не существует, но с другой стороны Нулевой оператор объединения (expr1) ?? (expr2)
В частности, не выдает уведомление, если значение левой стороны (expr1)
делает
не существует, просто как isset()
,
TernaryOperator левый ассоциативный
((true ? 'true' : false) ? 't' : 'f');
Нулевой оператор объединения правильно ассоциативно
($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);
Нулевой оператор объединения (??)
$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);
Вот таблица, которая объясняет разницу и сходство между '??'
а также ?:
Специальное примечание: нулевой оператор слияния и троичный оператор является
выражение, и что оно не оценивает переменную, но
результат выражения. Это важно знать, если вы хотите
вернуть переменную по ссылке. Утверждение возврата $ foo ?? $ Бар; а также
вернуть $ var == 42? $ a: $ b; в функции возврата по ссылке будет
поэтому не работает и выдается предупреждение.
Запустил ниже на php интерактивный режим (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"
??
:??
это как «ворота», который пропускает только NULL. NULL
. ??
такой же как ( !isset() || is_null() )
?:
?:
это как ворота, которые позволяют anything falsy
через — в том числе NULL
0
, empty string
, NULL
, false
, !isset()
, empty()
.. все, что пахнет фальшивкой echo ($x ? $x : false)
?:
будет бросать PHP NOTICE
на неопределенный (unset
или же !isset()
) переменные??
а также ?:
..?:
когда
empty($x)
проверки!empty($x) ? $x : $y
можно сократить до $x ?: $y
if(!$x) { fn($x); } else { fn($y); }
можно сократить до fn(($x ?: $y))
??
когда
!isset() || is_null()
проверять $object = $object ?? new objClassName();
Тернарный оператор может быть сложен …
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 {}
Нулевой оператор Coalese может быть сложен …
$v = $x ?? $y ?? $z;
Это последовательность:
if(!isset($x) || is_null($x) ) {}
else if(!isset($y) || is_null($y) ) {}
else {}
Используя укладку, я могу сократить это:
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';
Круто, верно? 🙂
Они оба ведут себя по-разному, когда дело доходит до динамической обработки данных.
Если переменная пуста (»), объединение с нулем будет рассматривать переменную как истину, но сокращенный троичный оператор не будет. И это то, что нужно иметь в виду.
$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
Оба являются сокращениями для более длинных выражений.
?:
коротка для $a ? $a : $b
, Это выражение будет оцениваться в $ a, если $ a оценивается в ПРАВДА.
??
коротка для isset($a) ? $a : $b
, Это выражение будет иметь значение $ a, если $ a установлено и не равно нулю.
Их варианты использования перекрываются, когда $ a не определено или равно нулю. Когда $ a не определено ??
не будет выдавать E_NOTICE, но результаты будут такими же. Когда $ a равно нулю, результат тот же.
Прокрутите вниз этот Ссылка и просмотр раздела, он дает вам сравнительный пример, как показано ниже:
<?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; в противном случае он возвращает свой второй операнд.
По сути, использование оператора объединения делает автоматическую проверку на нуль в отличие от троичного оператора.
Кажется, есть плюсы и минусы в использовании любого ??
или же ?:
, Профи к использованию ?:
является то, что он оценивает false и null и «» то же самое. Дело в том, что он сообщает E_NOTICE, если предыдущий аргумент равен нулю. С ??
Преимущество заключается в том, что E_NOTICE нет, но недостатком является то, что он не оценивает false и null одинаково. Исходя из моего опыта, я видел, как люди начинают взаимозаменяемо использовать null и false, но затем они в конечном итоге прибегают к модификации своего кода в соответствии с использованием либо null, либо false, но не обоих. Альтернативой является создание более сложного троичного условия: (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---
Лично я думаю, что было бы неплохо, если бы будущая версия PHP включала еще один новый оператор: :?
который заменил приведенный выше синтаксис. то есть:
// $var = $false :? "true";
Этот синтаксис будет оценивать null, false и «» одинаково и не будет генерировать E_NOTICE …