有人能够解释一下PHP中的三元运算符简写(?:
)和null 合并运算符(??
)之间的区别吗?
它们在什么情况下会表现出不同的行为,在什么情况下又是相同的(如果有的话)?
$a ?: $b
对比。
$a ?? $b
有人能够解释一下PHP中的三元运算符简写(?:
)和null 合并运算符(??
)之间的区别吗?
它们在什么情况下会表现出不同的行为,在什么情况下又是相同的(如果有的话)?
$a ?: $b
对比。
$a ?? $b
Elvis ?:
如果第一个参数包含"true-ish"值(参见Loose comparisons with ==表的第一行,了解哪些值被认为是松散相等于true
),则返回第一个参数。否则返回第二个参数。
$result = $var ?: 'default';
// 是以下代码的缩写
$result = $var ? $var : 'default';
Null 合并运算符 ??
如果第一个参数已设置且不为 null
,则返回第一个参数。否则返回第二个参数。
$result = $var ?? 'default';
// 是以下代码的缩写
$result = isset($var) ? $var : 'default';
当你的第一个参数为null时,它们基本上是相同的,除了当你有一个未定义的变量时,null合并不会输出E_NOTICE
。PHP 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也会返回相同的响应。
当然,这总是假设第一个参数是null
。一旦它不再是null,那么你就会发现差异在于??
运算符总是返回第一个参数,而?:
简写只有在第一个参数为真时才返回,这取决于PHP如何将事物强制转换为布尔值。
所以:
$a = false ?? 'f'; // false
$b = false ?: 'g'; // 'g'
那么$a
将等于false
,$b
将等于'g'
。
$b = []; var_dump($b['a']['b']['c'] ?? 'default');
或者对于对象 $b = new Foo; var_dump($b->a()->b()->c() ?? 'default');
。 - Jack B$a = [];
时行为也会不同。详情见:https://3v4l.org/iCCa0 - Soullivaneuhphp -a
),执行以下操作。每行的注释显示结果。var_export (false ?? 'value2'); // false
var_export (true ?? 'value2'); // true
var_export (null ?? 'value2'); // value2
var_export ('' ?? 'value2'); // ""
var_export (0 ?? 'value2'); // 0
var_export (false ?: 'value2'); // value2
var_export (true ?: 'value2'); // true
var_export (null ?: 'value2'); // value2
var_export ('' ?: 'value2'); // value2
var_export (0 ?: 'value2'); // value2
??
??
就像一个“门”,只允许NULL通过。 NULL
。??
与(!isset() || is_null())
相同??
!isset() || is_null()
检查$object = $object ?? new objClassName();
$v = $x ?? $y ?? $z;
// This is a sequence of "SET && NOT NULL"s:
if( $x && !is_null($x) ){
return $x;
} else if( $y && !is_null($y) ){
return $y;
} else {
return $z;
}
?:
?:
就像一个门闸,可以让 任何假值
通过 - 包括 NULL
0
,空字符串
,NULL
,false
,!isset()
,empty()
X ? Y : Z
unset
或 !isset()
)变量,?:
会抛出 PHP NOTICE
?:
的用法empty()
,!isset()
,is_null()
等!empty($x) ? $x : $y
的三元操作简化为 $x ?: $y
if(!$x) { echo $x; } else { echo $y; }
简化为 echo $x ?: $y
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
// Source & Credit: http://php.net/manual/en/language.operators.comparison.php#95997
// This is basically a sequence of:
if( truthy ) {}
else if(truthy ) {}
else if(truthy ) {}
..
else {}
if( isset($_GET['name']) && !is_null($_GET['name'])) {
$name = $_GET['name'];
} else if( !empty($user_name) ) {
$name = $user_name;
} else {
$name = 'anonymous';
}
$name = $_GET['name'] ?? $user_name ?: 'anonymous';
if(!$x) { echo $x; } else { echo $y; }
缩短为echo $x ?: $y
。两者并不相等。条件必须是if($x)
,而不是否定。它仍然让我学习了一些关于这个新的操作符的知识,所以帖子得到了赞。 - Soul Reaverelseif
作为单个单词以符合 PSR-12 编码标准。我知道你只是在演示,但首先检查 isset($_GET['name']) && !is_null($_GET['name'])
是多余的检查。 - mickmackusa$_GET['username']
未设置时,它会导致一个提示:$val = $_GET['username'] ?: 'default';
$val = isset($_GET['username']) ? $_GET['username'] : 'default';
空值合并运算符相当于上面的语句,如果$_GET['username']
未设置或为null
,则返回'default':$val = $_GET['username'] ?? 'default';
null
)值:$val = $input1 ?? $input2 ?? $input3 ?? 'default';
$var = empty($other_var) ? 'default_value' : $other_var;
。请注意,这不包括 ''
、null
、false
和 0
。 - St3anTernary Operator expression expr1 ?: expr3
returns expr1
if expr1
evaluates to
TRUE
but on the other hand Null Coalescing Operator expression (expr1) ?? (expr2)
evaluates to expr1
if expr1
is not NULL
Ternary
Operator expr1 ?: expr3
emit a notice if the left-hand side
value (expr1)
does not exist but on the other hand Null Coalescing Operator (expr1) ?? (expr2)
In particular, does not emit a notice if the left-hand side value (expr1)
does
not exist, just like isset()
.
TernaryOperator is left associative
((true ? 'true' : false) ? 't' : 'f');
Null Coalescing Operator is right associative
($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 合并运算符 (??)
$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);
这里是一张表格,解释了'??'
和?:
之间的区别和相似之处:
特别说明:空合并运算符和三元运算符是表达式,它们不会计算出一个变量,而是计算出一个表达式的结果。如果您想通过引用返回一个变量,则需要了解这一点。在返回引用的函数中,语句 return $foo ?? $bar; 和 return $var == 42 ? $a : $b; 将不能正常工作,并会发出警告。
当涉及到动态数据处理时,它们的行为方式是不同的。
如果变量为空(''),空合并运算符将把变量视为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
如果第一个操作数存在且不为 NULL,则返回它;否则返回第二个操作数。
- Simon两者都是更长表达式的简写。
?:
是 $a ? $a : $b
的缩写。如果 $a 的值为TRUE,则该表达式将求值为 $a。
??
是 isset($a) ? $a : $b
的缩写。如果 $a 被设置且不为 null,则该表达式将求值为 $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,则返回第一个操作数;否则返回第二个操作数。
实际上,使用合并运算符将自动检查null,而不像三元运算符。
a || b || c
模式,除了PHP的可以用于布尔值(false || 2
在JS中是2; false ?? 2
在PHP中是false)。 - fregante针对初学者:
空合并运算符(??)
除了 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
。
例如:
$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: ..
实用的简短回答:
尝试:
var_dump('' ?: 'ok'); // prints: ok
对
var_dump('' ?? 'ok'); // prints empty string
简写三元运算符(?:
)将返回左侧的值,如果左侧的值评估为“真实”的内容;否则将返回右侧的值。
而
空合并运算符(??
)将在左侧的值被声明且不为空时返回左侧的值;否则将返回右侧的值。
换句话说,?:
测试真实性,??
作为isset()
的简写。
*注意:如果你想用?:
测试一个变量,你必须先确保它已经被初始化/设置,否则PHP会抛出一个E_NOTICE
(而??
不会)。
$a ?: 'fallback'
等价于 $a ? $a : 'fallback'
,而 $a ?? 'fallback'
等价于 $a = isset($a) ? $a : 'fallback'
。0
,''
,false
,[]
,...)??
的展开中不应该有 $a =
。$a ?? 'fallback'
并不会 设置或更改 $a 的值。(它只是返回一个值)。 - Doin
php -a
)。然后设置ini_set('error_reporting', 'E_ALL')
和ini_set('display_errors', 'on')
。接着你可以尝试var_dump($var ?? 'default'))
,看看在此之前设置任何类型的值会发生什么。 - St3anexpr1 ?: expr3
如果expr1
为真,则返回expr1
,否则返回expr3
。 - Basj