PHP三元运算符vs null合并运算符

问题描述 投票:249回答:12

有人可以解释PHP中三元运算符速记(?:)和空合并运算符(??)之间的差异吗?

他们什么时候表现不同,以同样的方式(如果这种情况发生)?

$a ?: $b

VS.

$a ?? $b
php php-7 ternary-operator null-coalescing-operator
12个回答
267
投票

当你的第一个参数为null时,它们基本相同,只是当你有一个未定义的变量时,null合并将不会输出E_NOTICEPHP 7.0 migration docs有这样说:

对于需要将三元组与isset()结合使用的常见情况,已添加空合并运算符(??)作为语法糖。它返回第一个操作数(如果存在且不为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。一旦它不再为空,那么你最终会有差异,因为??运算符总会返回第一个参数,而?:速记只有在第一个参数是真的时才会返回,而这依赖于PHP would type-cast things to a boolean

所以:

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

然后qazxsw poi等于qazxsw poi和qazxsw poi等于$a


1
投票
(isset($something) or !$something) ? $something : $something_else

1
投票

其他答案很深入并给出了很好的解释。对于那些寻求快速回答的人,

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

$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--- :?


主要区别在于左侧运算符是:

  • 一个非零的虚假值(// $var = $false :? "true";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. $a ?: 'fallback'$a ? $a : 'fallback',...)
  • 未定义的变量

0
投票

$a ?? 'fallback'只执行两项任务:它检查$a = isset($a) ? $a : 'fallback'0。看看下面的例子:

''

上面的代码示例声明false以相同的方式处理不存在的变量和设置为[]的变量。

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更好地处理未定义的变量。然而,NULLNull 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


0
投票

当使用像$ _GET或$ _REQUEST这样的超级全局时,你应该知道它们可能是一个空字符串。在这个例子的例子中

ternary operator

将失败,因为$ username的值现在是一个空字符串。

因此,当使用$ _GET甚至$ _REQUEST时,您应该使用三元运算符,如下所示:

ternary operator

现在$ username的值是'nobody',如预期的那样。


64
投票

如果您使用这样的快捷方式三元运算符,如果未设置false,它将引发通知:

$b

所以你必须做这样的事情:

'g'

空合并运算符等效于上述语句,如果未设置$_GET['username']或者为$val = $_GET['username'] ?: 'default'; ,则返回'default':

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

请注意,它不会检查真实性。它仅检查是否已设置且不为空。

您也可以这样做,并返回第一个定义的(set而不是$_GET['username'])值:

null

现在这是一个合适的合并运算符。


40
投票

主要区别在于

  1. 如果$val = $_GET['username'] ?? 'default'; 评估为null,则三元运算符表达式$val = $input1 ?? $input2 ?? $input3 ?? 'default'; 返回expr1 ?: expr3但另一方面,如果expr1不是expr1,则Null Coalescing Operator表达式TRUE评估为(expr1) ?? (expr2)
  2. 如果左侧值expr1不存在但是另一方面Null Coalescing Operator expr1,则三元运算符NULL发出通知。如果左侧值expr1 ?: expr3不存在,则不发出通知,就像(expr1)一样。
  3. TernaryOperator是左关联的 (expr1) ?? (expr2) Null Coalescing Operator是右关联的 (expr1)

现在让我们解释一下示例之间的区别:

三元运算符isset()

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

Null Coalescing Operator ($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);

特别注意:null合并运算符和三元运算符是一个表达式,它不会计算变量,而是表达式的结果。知道是否要通过引用返回变量很重要。声明返回$ foo ?? $酒吧;并返回$ var == 42? $ a:$ b;因此,在按引用返回功能中将不起作用并发出警告。


38
投票

在php交互模式(终端上的'??')上进行以下操作。每行的注释显示结果。

?:

So this is my interpretation:

1. Null Coalescing运算符 - enter image description here

  • php -a就像一个只允许NULL通过的“门”。
  • 所以,它总是返回第一个参数,除非第一个参数碰巧是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"
  • 这意味着????相同

2.三元运算符 - NULL

  • ??就像一个让( !isset() || is_null() )通过的大门 - 包括?:
  • qazxsw poi,qazxsw poi,qazxsw poi,?:anything falsyNULL ..任何闻到麻痹的东西
  • 就像经典的三元运算符:0
  • 注意:empty string将在未定义(NULLfalse)变量上抛出!isset()

所以医生,我什么时候使用empty()echo ($x ? $x : false) ..

  • 我只是在开玩笑 - 我不是医生,这只是一种解释
  • 我会用?:PHP NOTICE检查 像unset这样的经典三元运算可以缩短为!isset() ??可缩短为?:
  • 我会用?: 我想做empty($x)检查 例如检查一个物体是否存在 - !empty($x) ? $x : $y

4.堆叠操作员......

  1. 三元运算符可堆叠... $x ?: $y if(!$x) { fn($x); } else { fn($y); } 这基本上是一系列: fn(($x ?: $y))
  2. Null Coalese操作员可堆叠... ?? 这是一系列: !isset() || is_null()
  3. 使用堆叠,我可以缩短这个: $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 很酷,对吗? :-)

13
投票

在动态数据处理方面,它们的行为都不同。

如果变量为空(''),则空合并将把变量视为true,但速记三元运算符则不会。这是需要考虑的事情。

Source & credit for this code

并输出:

if( truthy ) {}
else if(truthy ) {}
else if(truthy ) {}
..
else {}

链接:$v = $x ?? $y ?? $z;


9
投票

两者都是较长表达的缩写。

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']; } 的缩写。如果$ a的计算结果为TRUE,则此表达式将计算为$ a。

$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'; 的缩写。如果设置了$ a,则此表达式将计算为$ a,而不是null。

当$ a未定义或为null时,它们的用例重叠。当$ a未定义时,1b 2b 2d 1f Notice: Undefined variable: e in /in/ZBAa1 on line 21 2f 将不会产生E_NOTICE,但结果是相同的。当$ a为null时,结果是相同的。


4
投票

对于初学者:

空结合运算符(??)

除了https://3v4l.org/ZBAa1值和undefined(变量/数组索引/对象属性)之外,一切都是正确的

例如:

?:

这基本上是检查变量(数组索引,对象属性等)是否存在而不是$a ? $a : $b。类似于??功能

三元运算符速记(?:)

每一个虚假的东西(isset($a) ? $a : $b??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

希望这可以帮助


3
投票

向下滚动isset链接并查看该部分,它为您提供了一个比较示例,如下所示:

false

但是,不建议将运算符链接起来,因为稍后在阅读时会更难理解代码。

对于需要将三元组与isset()结合使用的常见情况,已添加空合并运算符(??)作为语法糖。它返回第一个操作数(如果存在且不为NULL);否则返回第二个操作数。

本质上,使用合并运算符将使其自动检查null,而不像三元运算符。


2
投票

使用null0似乎有利有弊。使用Notice的专家是它评估false和null和“”相同。如果前面的参数为null,它会报告E_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: .. ,pro是没有E_NOTICE,但con是它不评估false和null相同。根据我的经验,我看到人们开始使用null和false互换,但随后他们最终会修改他们的代码以使用null或false,但不能同时使用。另一种方法是创建一个更精细的三元条件:this

以下是使用null和false的<?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'; ?> 运算符的区别示例:

??

然而,通过详细说明三元运算符,我们可以使一个假或空字符串“”表现得好像它是一个null而不抛出一个e_notice:

?:

就个人而言,我认为如果PHP的未来版本包括另一个新的运算符:?:取代上述语法,那将是非常好的。即:??该语法将评估null,false和“”同等而不抛出E_NOTICE ...

© www.soinside.com 2019 - 2024. All rights reserved.