php троичный оператор против оператора слияния

<p>может ли кто-нибудь объяснить разницу между сокращенным выражением троичного оператора (<code>?:</code>) и оператором объединения нулей (<code>??</code>) в php?</p><p>когда они ведут себя по-разному и когда одинаково (если это вообще происходит)?</p><pre><code>$a ?: $b </code></pre><p>vs.</p><pre><code>$a ?? $b </code></pre>

<p>когда ваш первый аргумент равен нулю, они в основном одинаковы, за исключением того, что объединение нулей не будет выводить <code>e\_notice</code>, когда у вас есть неопределенная переменная. документация по миграции для <a href="http://php.net/manual/en/migration70.new-features.php#migration70.new-features.null-coalesce-op">php 7.0</a> имеет следующее:</p><blockquote> <p>нулевой оператор объединения (??) был добавлен как синтаксический сахар для общего случая необходимости использования троичного в сочетании с исеть (). возвращает свой первый операнд, если он существует и не равен null; в противном случае он возвращает свой второй операнд.</p> </blockquote><p>вот пример кода, чтобы продемонстрировать это:</p><pre><code><?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"; </code></pre><p>и это вывод:</p><pre><code>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 </code></pre><p>линии, которые имеют уведомление, являются теми, где я использую сокращенный тернарный оператор, а не оператор объединения нулей. однако даже с уведомлением php ответ будет таким же.</p><p>выполните код: <a href="https://3v4l.org/mcavc">https://3v4l.org/mcavc</a> </p><p>конечно, это всегда предполагает, что первый аргумент <code>null</code>. как только он перестанет иметь значение null, вы получите различия в том, что оператор <code>??</code> всегда будет возвращать первый аргумент, а сокращение <code>?:</code> будет только в том случае, если первый аргумент верен, и это зависит от того, как <a href="http://php.net/manual/en/language.types.boolean.php#language.types.boolean.casting">php будет печатать передать вещи в логическое значение</a> .</p><p>так:</p><pre><code>$a = false ?? 'f'; $b = false ?: 'g'; </code></pre><p>тогда <code>$a будет равен false, а $b</code> равен <code>'g'</code>.</p>

<p>если вы используете сокращенный троичный оператор, подобный этому, это вызовет уведомление, если <code>$_get['username'] не установлен:$val = $_get['username'] ?: 'default'; поэтому вместо этого вы должны сделать что-то вроде этого:$val = isset($_get['username']) ? $\_get['username'] : 'default'; </code></pre><p><strong> оператор объединения нулей </strong>эквивалентен вышеприведенному выражению и вернет значение «по умолчанию», если <code>$_get['username'] не установлен или null:$val = $_get['username'] ?? 'default'; обратите внимание, что<strong> это не проверяет правдивость </strong>. он проверяет, только если он установлен, а не ноль.вы также можете сделать это, и будет возвращено первое<strong> определенное </strong>(установленное, а не null) значение:$val = $input1 ?? $input2 ?? $input3 ?? 'default'; теперь это правильный оператор объединения.

основное отличие состоит в том, что  <strong>тернарное выражение</strong> выражение expr1 ?: expr3 возвращает expr1, если expr1 оценивается как true, но с другой стороны <strong>null coalescing operator</strong> выражение (expr1) ?? (expr2) оценивается как expr1, если expr1 <strong>not</strong> null <strong>ternary оператор</strong> expr1 ?: expr3 отправляет уведомление, если левая сторона значение (expr1) не существует, но с другой стороны <strong>null coalescing operator</strong> (expr1) ?? (expr2) в частности, не отправляет уведомление, если левостороннее значение (expr1) не имеет не существует, как и isset().  <strong>ternaryoperator</strong> оставлен ассоциативным  ((true ? 'true' : false) ? 't' : 'f');  <strong>нулевой оператор слияния</strong> является ассоциативным справа  ($a ?? ($b ?? $c)); </code></pre></li> </ol><p>теперь давайте объясним разницу между примерами: </p><p><strong>тернарный оператор</strong> <code>(?:)</code> </p><pre><code>$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); <strong>нулевой оператор объединения</strong> (??)$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); вот таблица, которая объясняет разницу и сходство между '??' и ?:  <a href="https://i.stack.imgur.com/2msbo.png"> <img src="https://i.stack.imgur.com/2msbo.png" alt="enter image description here">  <blockquote> специальное примечание: оператор объединения нулей и троичный оператор - это выражение, и что он не оценивается для переменной, но для результат выражения. это важно знать, если вы хотите вернуть переменную по ссылке. утверждение возврата $ foo ?? $ бар; а также вернуть $ var == 42? $ a: $ b; в функции возврата по ссылке будет поэтому не работает и выдается предупреждение.</p> </blockquote>

<p>запустите ниже в php интерактивный режим (<code>php -a</code> на терминале). комментарий в каждой строке показывает результат.</p><pre><code>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" </code></pre><h1> <strong>так вот моя интерпретация:</strong></h1><h2> 1. нулевой оператор слияния - <code>??</code>:</h2><ul> <li><strong><code>??</code> похож на «гейт», который пропускает только null через</strong>. </li> <li>итак, <strong><em>всегда возвращает первый параметр</em></strong>, если только <strong><em>первый параметр <code>null</code></em></strong>. </li> <li>это означает, что <code>??</code> такой же, как <code>( !isset() || is\_null() )</code></li> </ul><h2>2. тернарный оператор - <code>?:</code></h2><ul> <li><strong><code>?:</code> похож на ворота, которые пропускают <em><code>anything falsy</code></em> - включая <code>null</code></strong></li> <li><code>0</code>, <code>empty string</code>, <code>null</code>, <code>false</code>, <code>!isset()</code>, <code>empty()</code> .. все, что пахнет фальшивкой </li> <li>так же, как классический троичный оператор: <code>echo ($x ? $x : false)</code> </li> <li>примечание: <code>?:</code> сгенерирует <code>php notice</code> для неопределенных (<code>unset</code> или <code>!isset()</code>) переменных</li> </ul><h2>3. итак, доктор, когда я использую <code>??</code> и <code>?:</code> ..</h2><ul> <li>я только шучу - я не врач, и это просто интерпретация </li> <li>я бы использовал <code>?:</code> когда <ul> <li>делать проверки <code>empty($x) классическая троичная операция, такая как !empty($x) ? $x : $y</code>, может быть сокращена до <code>$x ?: $y</code> </li> <li><code>if(!$x) { fn($x); } else { fn($y); } можно сократить до fn(($x ?: $y))   я бы использовал ?? когда  я хочу сделать проверку !isset() || is_null()  например, проверить, существует ли объект - $object = $object ?? new objclassname();  4. штабелирование операторов ... <strong>тернарный оператор может быть сложен</strong> ...  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   <a href="http://php.net/manual/en/language.operators.comparison.php#95997">источник и кредит для этого кода  это в основном последовательность: if( truthy ) {} else if(truthy ) {} else if(truthy ) {} .. else {}  <strong>нулевой оператор coalese может быть сложен</strong> ...  $v = $x ?? $y ?? $z;  это последовательность: if(!isset($x) || is\_null($x) ) {} else if(!isset($y) || is\_null($y) ) {} else {}  <strong>используя укладку, я могу сократить это:</strong> if(!isset($\_get['name'])){ if(isset($user_name) && !empty($user\_name)){ $name = $user\_name; }else { $name = 'anonymous'; } } else { $name = $_get['name']; }  <strong>к этому:</strong> $name = $_get['name'] ?? $user\_name ?: 'anonymous'; </code></pre> <p>круто, верно? :-)</p></li> </ol>

<p>они оба ведут себя по-разному, когда дело доходит до динамической обработки данных.</p><p>если переменная пуста (''), объединение с нулем будет рассматривать переменную как истину, но сокращенный троичный оператор не будет. и это то, что нужно иметь в виду.</p><pre><code>$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'; </code></pre><p>и вывод:</p><pre><code>1b 2b 2d 1f notice: undefined variable: e in /in/zbaa1 on line 21 2f </code></pre><p>ссылка: <a href="https://3v4l.org/zbaa1">https://3v4l.org/zbaa1</a> </p>

<p>оба являются сокращениями для более длинных выражений.</p><p><code>?:</code> - это сокращение от <code>$a ? $a : $b. это выражение оценивается как $ a, если $ a оценивается как<strong>true</strong>.?? - это сокращение от isset($a) ? $a : $b</code>. это выражение будет иметь значение $ a, если $ a установлено и не равно нулю.</p><p>их варианты использования перекрываются, когда $ a не определено или равно нулю. когда $ a не определено, <code>??</code> не выдаст e\_notice, но результаты будут такими же. когда $ a равно нулю, результат тот же.

прокрутите вниз по ссылке <a href="http://php.net/manual/en/migration70.new-features.php">this и просмотрите раздел, он даст вам сравнительный пример, как показано ниже:<?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'; ?> </code></pre><p>однако не рекомендуется объединять операторы в цепочку, так как это усложняет понимание кода при его чтении в дальнейшем.</p><blockquote> <p>нулевой оператор объединения (??) был добавлен как синтаксический сахар для общего случая необходимости использования троичного в сочетании с isset (). возвращает свой первый операнд, если он существует и не равен null; в противном случае он возвращает свой второй операнд.</p> </blockquote><p>по сути, использование оператора объединения делает автоматическую проверку на нуль в отличие от троичного оператора.</p>

<p>кажется, есть плюсы и минусы использования <code>??</code> или <code>?:</code>. преимущество использования <code>?:</code> состоит в том, что он оценивает false и null и "" то же самое. дело в том, что он сообщает e\_notice, если предыдущий аргумент равен нулю. с <code>??</code> преимущество состоит в том, что e\_notice нет, но дело в том, что он не оценивает false и null одинаково. исходя из моего опыта, я видел, как люди начинают взаимозаменяемо использовать null и false, но затем они в конечном итоге прибегают к модификации своего кода в соответствии с использованием либо null, либо false, но не обоих. альтернативой является создание более сложного троичного условия: <code>(isset($something) or !$something) ? $something : $something\_else</code>.</p><p>ниже приведен пример различия использования оператора <code>??</code> с использованием как null, так и false: </p><pre><code>$false = null; $var = $false ?? "true"; echo $var . "---<br>";//returns: true--- $false = false; $var = $false ?? "true"; echo $var . "---<br>"; //returns: --- </code></pre><p>однако, развивая троичный оператор, мы можем заставить ложную или пустую строку "" вести себя так, как если бы она была нулевой, не бросая e\_notice:</p><pre><code>$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--- </code></pre><p>лично я думаю, что было бы неплохо, если бы будущая версия php включала еще один новый оператор: <code>:?</code>, который заменил приведенный выше синтаксис. то есть: <code>// $var = $false :? "true";</code> этот синтаксис будет оценивать null, false и "" одинаково и не выбрасывать e\_notice ...</p>

<pre><code>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. </code></pre>

<p><code>null coalescing operator</code> выполняет только две задачи: проверяет <code>whether the variable is set</code> и <code>whether it is null</code>. посмотрите на следующий пример:</p><pre><code><?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' </code></pre><p><em>в приведенном выше примере кода говорится, что <code>null coalescing operator</code> обрабатывает несуществующую переменную и переменную, для которой установлено значение <code>null</code> таким же образом.</em></p><p><code>null coalescing operator</code> является улучшением по сравнению с <code>ternary operator</code>. взгляните на следующий фрагмент кода, сравнивая их:</p><pre><code><?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 предназначен для обработки неопределенных переменных лучше, чем ternary operator. принимая во внимание, что ternary operator является сокращением для if-else.null coalescing operator не предназначен для замены ternary operator, но в некоторых случаях использования, таких как в приведенном выше примере, он позволяет писать чистый код с меньшими хлопотами.кредиты: <a href="http://dwellupper.io/post/6/php7-null-coalescing-operator-usage-and-examples">http://dwellupper.io/post/6/php7-null-coalescing-operator-usage-and-examples 

когда вы используете суперглобальные переменные, такие как $ \_get или $ _request, вы должны знать, что они могут быть пустой строкой.$username = $_get['user'] ?? 'nobody'; потерпит неудачу, потому что значение $ username теперь является пустой строкой.</p><p>поэтому при использовании $ _get или даже $ \_request вы должны использовать вместо этого троичный оператор, например:</p><pre><code>$username = (!empty($\_get['user'])?$_get['user']:'nobody'; теперь значение $ username равно «nobody», как и ожидалось.</p>