PHP 猫王运算符与空合并运算符

PHP Elvis operator vs null coalescing operator

谁能解释一下 ternary operator shorthand (?:) and null coalescing operator (??) 和 PHP 之间的区别?

他们什么时候行为不同,什么时候行为相同(如果发生这种情况)?

$a ?: $b

VS.

$a ?? $b

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

<?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';
?>

The null coalescing operator (??) has been added as syntactic sugar for the common case of needing to use a ternary in conjunction with isset(). It returns its first operand if it exists and is not NULL; otherwise it returns its second operand.

本质上,与三元运算符不同,使用合并运算符将使它自动检查 null。

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

The null coalescing operator (??) has been added as syntactic sugar for the common case of needing to use a ternary in conjunction with isset(). It returns its first operand if it exists and is not NULL; otherwise it returns its second operand.

下面是一些示例代码来演示这一点:

<?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";

有通知的行是我使用 shorthand 三元运算符而不是空合并运算符的行。但是,即使有通知,PHP 也会给出相同的回复。

执行代码:https://3v4l.org/McavC

当然,这总是假设第一个参数是null。一旦它不再为 null,那么您最终会发现差异,因为 ?? 运算符总是 return 第一个参数,而 ?: shorthand 仅当第一个参数是真实的,这取决于 PHP would type-cast things to a boolean.

所以:

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

然后 $a 等于 false 并且 $b 等于 'g'.

在动态数据处理方面,两者的行为不同。

如果变量为空 ( '' ),null 合并会将变量视为 true,但 shorthand 三元运算符不会。这是要记住的事情。

$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

Link: https://3v4l.org/ZBAa1

像这样使用快捷三元运算符,如果没有设置$_GET['username']会引起提示:

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

所以你必须这样做:

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

null coalescing operator等价于上面的语句,如果$_GET['username']没有设置或者是return'default' =16=]:

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

请注意它不检查真实性。它只检查它是否已设置而不是 null。

您也可以这样做,第一个 defined(设置而不是 null)值将是 returned:

$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 的未来修订版包含另一个新运算符::? 来取代上述语法,那就太好了。 IE: // $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 的 shorthand。

Null Coalescing operator 并不是要取代 ternary operator,但在某些用例中,例如上面的示例,它可以让您轻松编写干净的代码。

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

主要区别在于

  1. 三元运算符 表达式 expr1 ?: expr3 returns expr1 if expr1 的计算结果为 TRUE 但另一方面 空合并运算符 表达式 (expr1) ?? (expr2) 如果 expr1 不是 NULL

  2. ,计算结果为 expr1
  3. 三元 运算符 expr1 ?: expr3 如果左侧 值 (expr1) 不存在,但另一方面 Null Coalescing Operator (expr1) ?? (expr2) 特别是,如果左侧值 [=23] 不发出通知=] 确实 不存在,就像 isset()

  4. 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);

这里是解释'??'?:之间异同的table

Special Note : null coalescing operator and ternary operator is an expression, and that it doesn't evaluate to a variable, but to the result of an expression. This is important to know if you want to return a variable by reference. The statement return $foo ?? $bar; and return $var == 42 ? $a : $b; in a return-by-reference function will therefore not work and a warning is issued.

运行 以下 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通过.
  • 所以,它总是returns第一个参数,除非第一个参数恰好是 NULL.
  • 这意味着 ??( !isset() || is_null() )
  • 相同

使用??

  • 缩短!isset() || is_null() 检查
  • 例如$object = $object ?? new objClassName();

堆叠 Null 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; 
        }

三元运算符?:

  • ?: 就像一扇门,让 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 的计算结果为 TRUE.

,则此表达式的计算结果为 $a

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

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

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

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

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

因此,当使用 $_GET 甚至 $_REQUEST 时,您应该像这样使用三元运算符:

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

现在 $username 的值是预期的 'nobody'。

初学者:

空合并运算符 (??)

除了 null 值和未定义的(variable/array index/object 属性)

之外,一切都是真的

例如:

$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 函数

三元运算符shorthand(?:)

所有错误的东西(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');

var_dump('' ?? 'ok');

如果测试值(或变量*计算为,第一个将return 'ok' false

如果测试值(或变量*,第二个将return'ok'null 是否initialized/set.


*注意:如果你想用 ?: 测试一个 变量 ,你必须首先确保它是 initialized/set,否则 PHP将引发 E_NOTICE(而 ?? 不会)。