有人可以解释PHP中三元运算符速记(?:
)和空合并运算符(??
)之间的差异吗?
他们什么时候表现不同,以同样的方式(如果发生这种情况)?
$a ?: $b
VS
$a ?? $b
答案 0 :(得分:239)
当你的第一个参数为null时,它们基本相同,只是当你有一个未定义的变量时,空合并将不会输出E_NOTICE
。 PHP 7.0 migration docs可以这样说:
空合并运算符(??)已添加为语法糖 对于需要使用三元组的常见情况 isset()函数。它返回第一个操作数(如果存在且不为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也会给出相同的响应。
当然,这总是假设第一个参数是null
。一旦它不再为null,那么你最终会产生差异,??
运算符将始终返回第一个参数,而?:
简写只有在第一个参数是真的时才会返回,并且这取决于{ {3}}
所以:
$a = false ?? 'f';
$b = false ?: 'g';
然后将$a
等于false
且$b
等于'g'
。
答案 1 :(得分:61)
如果您使用这样的快捷方式三元运算符,如果未设置$_GET['username']
,则会发出通知:
$val = $_GET['username'] ?: 'default';
所以你必须做这样的事情:
$val = isset($_GET['username']) ? $_GET['username'] : 'default';
null合并运算符等同于上述语句,如果未设置$_GET['username']
或null
,则会返回'default':
$val = $_GET['username'] ?? 'default';
请注意不检查真实性。它仅检查它是否已设置且不为空。
您也可以这样做,并且会返回第一个已定义的(设置而不是null
)值:
$val = $input1 ?? $input2 ?? $input3 ?? 'default';
现在这是一个合适的合并算子。
答案 2 :(得分:38)
主要区别在于
三元运算符表达式expr1 ?: expr3
如果expr1
评估为expr1
则返回TRUE
(expr1) ?? (expr2)
但另一方面空合并运算符表达式expr1
如果expr1
不 NULL
expr1 ?: expr3
<强>三元
如果是左侧,话务员 (expr1)
会发出通知
值(expr1) ?? (expr2)
不存在但另一方面空的合并运算符 (expr1)
特别是,如果左侧值isset()
不发出通知,则不会发出通知
不存在,就像((true ? 'true' : false) ? 't' : 'f');
一样。
TernaryOperator 是左关联的
($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);
'??'
下面是解释?:
和dataframe
特别注意:null合并运算符和三元运算符是一个 表达式,并且它不会评估变量,而是评估变量 表达的结果。知道您是否愿意这一点非常重要 通过引用返回变量。声明返回$ foo ?? $酒吧;和 返回$ var == 42? $ a:$ b;在按引用返回的功能中 因此不起作用并发出警告。
答案 3 :(得分:33)
在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 {}
可以堆叠Null 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';
很酷,对吗? : - )
答案 4 :(得分:12)
在动态数据处理方面,它们的行为都不同。
如果变量为空(&#39;&#39;),则空值合并会将变量视为真,但速记三元运算符不会被取消。这是值得考虑的事情。
jQuery(document.body).on('click', '.page', function() {
var randomClass = 3;
var randomNumber = Math.round(Math.random() * (randomClass - 1)) + 1;
jQuery(this).addClass("activated").addClass('scaled-' + randomNumber);
var wrapper_scrollTop = $("#wrapper").scrollTop(); //gets amount scrolled
var half_wrapper = $("#wrapper").height()*(0.5); //50% of wrapper height
jQuery(this).css("top",half_wrapper+wrapper_scrollTop);
jQuery(document.body).on('click', '.activated', function() {
jQuery(this).removeClass("activated scaled-1 scaled-2 scaled-3");
jQuery(this).css("top","") //returns top to original value specified in css
});
});
输出:
$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';
答案 5 :(得分:9)
两者都是较长表达式的简写。
?:
是$a ? $a : $b
的缩写。如果$ a的值为 TRUE ,则该表达式的值为$ a。
??
是isset($a) ? $a : $b
的缩写。如果设置了$ a且不为null,则该表达式的计算结果为$ a。
当$ a未定义或为空时,它们的用例重叠。 $ a未定义时,??
不会产生E_NOTICE,但是结果是相同的。 $ a为null时,结果相同。
答案 6 :(得分:3)
向下滚动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';
?>
但是,不建议将操作符链接起来,因为稍后在阅读时会更难理解代码。
对于需要与isset()一起使用三元组的常见情况,添加了空合并运算符(??)作为语法糖。它返回第一个操作数(如果存在且不为NULL);否则它返回第二个操作数。
基本上,使用合并运算符会使其自动检查null,而不像三元运算符。
答案 7 :(得分:3)
其他答案更深入,并给出了很好的解释。对于那些寻求快速解答的人,
JSONAPISerializer
是$a ?: 'fallback'
同时
$a ? $a : 'fallback'
是$a ?? 'fallback'
主要区别在于左操作符为:
$a = isset($a) ? $a : 'fallback'
,0
,''
,false
,...)答案 8 :(得分:2)
使用??
或?:
似乎有利有弊。使用?:
的专业人员是它评估false和null以及&#34;&#34;相同。如果前面的参数为null,它会报告E_NOTICE。使用??
,pro是没有E_NOTICE,但是con是它不评估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: ---
然而,通过详细说明三元运算符,我们可以制作一个假的或空的字符串&#34;&#34;如果它没有抛出e_notice就像是一个null:
$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和&#34;&#34;同样地,不要抛出E_NOTICE ......
答案 9 :(得分:2)
对于初学者:
空合并运算符(??)
除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
,空字符串)都是假的,但是如果它是未定义的,它也是假的,但是Notice
会是假的扔
ex
$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: ..
希望这会有所帮助
答案 10 :(得分:1)
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 :(得分:0)
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
运算符旨在比ternary operator
更好地处理未定义的变量。鉴于ternary operator
是if-else
的缩写。
Null Coalescing operator
并不是要替换ternary operator
,但在上面示例中的某些用例中,它可以让您轻松编写干净的代码。
致谢:http://dwellupper.io/post/6/php7-null-coalescing-operator-usage-and-examples
答案 12 :(得分:0)
使用$ _GET或$ _REQUEST之类的超全局变量时,您应该意识到它们可能是一个空字符串。 在这种情况下,这个例子
$username = $_GET['user'] ?? 'nobody';
将失败,因为$ username的值现在是一个空字符串。
因此,在使用$ _GET甚至$ _REQUEST时,应使用三元运算符,如下所示:
$username = (!empty($_GET['user'])?$_GET['user']:'nobody';
现在$ username的值像预期的那样为“ nobody”。