PHP Elvis运算符vs空合并运算符

有人能解释一下PHP中三元运算符简写 (?:)和空合并运算符 (??)之间的区别吗?

他们什么时候表现不同,什么时候表现相同(如果真的发生了的话)?

$a ?: $b

VS。

$a ?? $b
224443 次浏览

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

<?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合并运算符(??)已被添加为语法糖,用于需要将三元值与isset()结合使用的常见情况。如果操作数存在且不为NULL,则返回第一个操作数;否则返回第二个操作数。

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

当你的第一个参数为空时,它们基本上是相同的,除了当你有一个未定义的变量时,空合并不会输出E_NOTICEPHP 7.0迁移文档是这样说的:

空合并运算符(??)已被添加为语法糖 对于一般情况下需要使用三元组合的 收取()。如果操作数存在且不为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会将内容类型转换为布尔类型

所以:

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

那么$a等于false,而$b等于'g'

当涉及到动态数据处理时,它们的行为都不同。

如果变量为空("),空合并将把变量视为真值,但速记三元操作符不会。这是需要记住的。

$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

链接:https://3v4l.org/ZBAa1

如果你像这样使用快捷三元操作符,如果没有设置$_GET['username'],它将引起一个通知:

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

所以你必须这样做:

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

空合并运算符等价于上面的语句,如果$_GET['username']未设置或为null,则返回'default':

$val = $_GET['username'] ?? 'default';

注意它不检查真实性.;它只检查它是否已设置且不为空。

你也可以这样做,并且将返回第一个定义 (set而不是null)值:

$val = $input1 ?? $input2 ?? $input3 ?? 'default';

这是一个合适的聚结算子。

使用???:似乎有利有弊。使用?:的好处是,它计算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
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 setwhether 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 operatorif-else的缩写。

Null Coalescing operator并不意味着要取代ternary operator,但在一些用例中,比如上面的例子,它可以让你更轻松地编写干净的代码。

学分:http://dwellupper.io/post/6/php7-null-coalescing-operator-usage-and-examples

主要的区别在于

  1. 三元运算符表达式expr1 ?: expr3返回expr1如果expr1计算为 TRUE,但另一方面空合并运算符表达式(expr1) ?? (expr2) 如果expr1 NULL

  2. ,则返回expr1 <李> < p > < >强三元 操作符 expr1 ?: expr3如果左边 (expr1)值不存在,但另一方面空合并运算符 (expr1) ?? (expr2)特别地,如果左边的值(expr1)存在,则不发出通知 不存在,就像isset()一样。李< / p > < / >
  3. TernaryOperator是左结合的

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

    空合并运算符是正确的结合

    ($a ?? ($b ?? $c));
    

Now lets explain the difference between by example :

Ternary Operator (?:)

$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);

下面的表格解释了'??'?:之间的区别和相似之处

enter image description here

特别注意:空合并运算符和三元运算符是一个 表达式,并且它的值不是一个变量,而是 表达式的结果。如果你想的话,知道这一点很重要 通过引用返回一个变量。语句返回$foo ??美元的酒吧;而且 返回$var == 42 ?$a: $b;在引用返回函数中

在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() )相同

??的使用

  • shorten !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;
}

三元运算符?:

  • ?:就像一个门,让anything falsy通过——包括NULL
  • 任何错误:0empty stringNULLfalse!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';

很酷,对吧?: -)

两者都是较长的表达式的简写。

?:$a ? $a : $b的缩写。如果$a的值为真正的,则该表达式的值为$a。

??isset($a) ? $a : $b的缩写。如果设置了$a且不为空,则该表达式将计算为$a。

当$a未定义或为空时,它们的用例重叠。当$a未定义时,??将不会产生E_NOTICE,但结果是相同的。当$a为空时,结果是相同的。

当使用像$_GET或$_REQUEST这样的超全局变量时,你应该注意它们可能是一个空字符串。 在这个特殊的情况下,这个例子

$username = $_GET['user'] ?? 'nobody';

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

所以当使用$_GET甚至$_REQUEST时,你应该像这样使用三元操作符:

$username = (!empty($_GET['user'])?$_GET['user']:'nobody';

现在$username的值是'nobody'。

对于初学者:

空合并运算符(??)

除了null值和undefined(变量/数组索引/对象属性)之外,所有内容都为真

例:

$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"

这基本上是检查变量(数组索引,对象属性..etc)是存在的,而不是null。类似于isset函数

三元运算符简写(?:)

每个假的东西(falsenull0,空字符串)都是假的,但如果它是一个未定义的,它也是假的,但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: ..

希望这能有所帮助

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

$a ?: 'fallback'$a ? $a : 'fallback'

$a ?? 'fallback'$a = isset($a) ? $a : 'fallback'


主要的区别在于左操作符是:

  • 一个非空的假值(0''false[],…)
  • 未定义的变量

实用简短回答:

试一试:

var_dump('' ?: 'ok');

vs

var_dump('' ?? 'ok');

如果测试值(或变量) 计算结果为 false,则第一个将返回'ok'

如果测试值(或变量) null 或未初始化/设置,则第二个返回'ok'


*警告:如果你想用?:测试变量,你必须首先确保它已初始化/设置,否则PHP将引发E_NOTICE(而??不会)。

:? -意思是如果第一个操作数为真,它将返回该操作数。否则,它将返回第二个。

?? -计算第一个操作数是否存在且不为空。如果是,则返回;否则,它返回第二个操作数。

我发现一篇文章很好地描述了这种差异: https://www.fparedes.com/blog/null-coalescing-vs-elvis-operator-php/ < / p >