有人可以解释 PHP 中 ternary operator shorthand (?:
) 和 null coalescing operator (??
) 之间的区别吗?
他们什么时候表现不同,什么时候表现相同(如果这种情况发生的话)?
$a ?: $b
VS。
$a ?? $b
php -a
)。然后是 ini_set('error_reporting', 'E_ALL')
和 ini_set('display_errors', 'on')
。然后你可以试试 var_dump($var ?? 'default'))
看看你在它之前设置了任何类型的值会发生什么
expr1
的计算结果为 true
,则表达式 expr1 ?: expr3
返回 expr1
,否则返回 expr3
。
当您的第一个参数为 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 would type-cast things to a boolean 的方式。
所以:
$a = false ?? 'f'; // false
$b = false ?: 'g'; // 'g'
那么 $a
等于 false
并且 $b
等于 'g'
。
在 php 交互模式下运行以下命令(终端上的 php -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 ??新的 objClassName();
堆叠空 Coalese 运算符
$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
注意: ?: 将在未定义(未设置或 !isset())变量上抛出 PHP NOTICE
用于 ?:
检查 empty()、!isset()、is_null() 等
缩短像 !empty($x) 这样的三元运算? $x : $y 到 $x ?: $y
缩短 if(!$x) { echo $x; } 其他 { 回声 $y; } 回显 $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)
,而不是否定。它仍然让我了解了一些关于这个操作符的知识,这在它的简短版本中对我来说是新的,所以帖子收到了赞成票。
elseif
作为单个词以符合 PSR-12 编码标准。我知道你只是在做一个演示,但是 isset($_GET['name']) && !is_null($_GET['name'])
首先是冗余检查。
如果您像这样使用快捷方式三元运算符,如果未设置 $_GET['username']
将导致通知:
$val = $_GET['username'] ?: 'default';
因此,您必须执行以下操作:
$val = isset($_GET['username']) ? $_GET['username'] : 'default';
null 合并运算符 等价于上述语句,如果 $_GET['username']
未设置或为 null
,将返回 'default':
$val = $_GET['username'] ?? 'default';
请注意,它不会检查真实性。它仅检查它是否已设置且不为空。
您也可以这样做,第一个 defined(设置而不是 null
)值将被返回:
$val = $input1 ?? $input2 ?? $input3 ?? 'default';
现在这是一个适当的合并运算符。
$var = empty($other_var) ? 'default_value' : $other_var;
。请注意,这不包括 ''
、null
、false
和 0
主要区别在于
三元运算符表达式 expr1 ?: 如果 expr1 的计算结果为 TRUE,则 expr3 返回 expr1 但另一方面,空合并运算符表达式 (expr1) ?? (expr2) 如果 expr1 不为 NULL 三元运算符 expr1 时计算为 expr1 ?: 如果左侧值 (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);
这是解释 '??'
和 ?:
之间的区别和相似之处的表格
https://i.stack.imgur.com/2MSbO.png
特别注意:空值合并运算符和三元运算符是一个表达式,它的计算结果不是变量,而是表达式的结果。了解是否要通过引用返回变量很重要。语句 return $foo ?? $酒吧;并返回 $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
It returns its first operand if it exists and is not NULL; otherwise it returns its second operand
的文档中清楚地指出了这一点。
两者都是较长表达式的简写。
?:
是 $a ? $a : $b
的缩写。如果 $a 的计算结果为 TRUE,则此表达式的计算结果为 $a。
??
是 isset($a) ? $a : $b
的缩写。如果设置了 $a 并且不为空,则此表达式将计算为 $a。
当 $a 未定义或为空时,它们的用例会重叠。当 $a 未定义时,??
不会产生 E_NOTICE,但结果是一样的。当 $a 为 null 时,结果是相同的。
对于初学者:
空合并运算符 (??)
除了 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: ..
希望这可以帮助
向下滚动 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。
a || b || c
模式,除了 PHP 可用于布尔值(JS 中的 false || 2
为 2;PHP 中的 false ?? 2
为 false)
其他答案很深入,并给出了很好的解释。对于那些寻求快速答案的人,
$a ?: 'fallback'
是 $a ? $a : 'fallback'
尽管
$a ?? 'fallback'
是 $a = isset($a) ? $a : 'fallback'
主要区别在于左运算符是:
一个不为空的假值(0、''、false、[]、...)
未定义的变量
??
的扩展中不应有 $a =
。 $a ?? 'fallback'
不设置或更改 $a 的值。 (它只返回一个值)。
使用 ??
或 ?:
似乎各有利弊。使用 ?:
的优点是它评估 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: ---
然而,通过详细说明三元运算符,我们可以使假或空字符串 "" 表现得就好像它是 null 而不会引发 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...
?? null ?:
的东西非常棒,谢谢先生。聪明的家伙。
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.
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
isset($_POST['fullname'])
已检查 NULL
值 - 所以第一个示例中的 && !is_null($_POST['fullname'])
无论如何都是多余的
当使用像 $_GET 或 $_REQUEST 这样的超全局变量时,你应该知道它们可能是一个空字符串。在这种特殊情况下,此示例
$username = $_GET['user'] ?? 'nobody';
将失败,因为 $username 现在的值是一个空字符串。
因此,当使用 $_GET 甚至 $_REQUEST 时,您应该使用三元运算符,如下所示:
$username = (!empty($_GET['user'])?$_GET['user']:'nobody';
现在 $username 的值正如预期的那样是 'nobody' 。
实用的简短回答:
尝试:
var_dump('' ?: 'ok');
对比
var_dump('' ?? 'ok');
如果测试值(或变量 *)评估为 false
,第一个将返回 'ok'
然而
如果测试值(或变量 *)是 null
或未初始化/设置,则第二个将返回 'ok'
。
*注意:如果你想用 ?:
测试一个变量,你必须首先确保它被初始化/设置,否则 PHP 会产生一个 E_NOTICE
(而 ??
不会)。
$b = []; var_dump($b['a']['b']['c'] ?? 'default');
或带有对象$b = new Foo; var_dump($b->a()->b()->c() ?? 'default');
$a = [];
的行为也不同。请参阅:3v4l.org/iCCa0