ChatGPT解决这个技术问题 Extra ChatGPT

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

有人可以解释 PHP 中 ternary operator shorthand (?:) 和 null coalescing operator (??) 之间的区别吗?

他们什么时候表现不同,什么时候表现相同(如果这种情况发生的话)?

$a ?: $b

VS。

$a ?? $b
测试它的一个好方法是在交互模式下使用 php 控制台 (php -a)。然后是 ini_set('error_reporting', 'E_ALL')ini_set('display_errors', 'on')。然后你可以试试 var_dump($var ?? 'default')) 看看你在它之前设置了任何类型的值会发生什么
通过谷歌搜索不容易找到:documentation可以省略三元运算符的中间部分。如果 expr1 的计算结果为 true,则表达式 expr1 ?: expr3 返回 expr1,否则返回 expr3

Y
Yaron U.

当您的第一个参数为 null 时,它们基本相同,只是当您有未定义的变量时,null 合并不会输出 E_NOTICEPHP 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 也会返回相同的响应。

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

当然,这总是假设第一个参数是 null。一旦它不再为 null,那么您最终会发现不同之处在于 ?? 运算符将始终返回第一个参数,而 ?: 简写仅在第一个参数为真时才会返回,这取决于 PHP would type-cast things to a boolean 的方式。

所以:

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

那么 $a 等于 false 并且 $b 等于 'g'


提示:如果你一直在使用??而不是 ?: 但后来发现自己需要使您的代码与 PHP 7 之前的版本兼容(对于 ex 的插件),那么您可能想要换掉 ??用 isset($something) 吗? $something : $something_else 在你的代码中无处不在。您可以使用 Notepad++ 或 nedit(以及其他编辑器)使用查找/替换工具轻松完成此操作,选择正则表达式选项并在查找字段中插入:“\s*(\S+)\s*\?\?”并在替换字段中: " isset($1) ? $1 :" 不带引号(nedit 使用 \1 而不是 $1)。然后全部更换。
这是正确的答案,但真实性检查是主要区别,应该更加强调。
@MasterOdin 对您的回答不满意。两者都不相同。有不同的结果。
值得注意的是,您可以使用 ??与链接。例如:$b = []; var_dump($b['a']['b']['c'] ?? 'default'); 或带有对象 $b = new Foo; var_dump($b->a()->b()->c() ?? 'default');
请注意,$a = []; 的行为也不同。请参阅:3v4l.org/iCCa0
a
a20

在 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),而不是否定。它仍然让我了解了一些关于这个操作符的知识,这在它的简短版本中对我来说是新的,所以帖子收到了赞成票。
在 php 中,请始终使用 elseif 作为单个词以符合 PSR-12 编码标准。我知道你只是在做一个演示,但是 isset($_GET['name']) && !is_null($_GET['name']) 首先是冗余检查。
这是了解这些运算符如何工作的一个很好的答案,但我希望我永远不必对在一个语句中使用两个运算符的生产代码进行故障排除!
A
Andrew

如果您像这样使用快捷方式三元运算符,如果未设置 $_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;。请注意,这不包括 ''nullfalse0
D
Dhairya Lakhera

主要区别在于

三元运算符表达式 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;因此,在按引用返回的函数中将不起作用并发出警告。


C
Chazy Chaz

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

如果变量为空 ( '' ),则空值合并会将变量视为 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

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


这对于 PHP 来说显然是违反直觉的,空字符串通常被认为是错误的。然而,在 ??: It returns its first operand if it exists and is not NULL; otherwise it returns its second operand 的文档中清楚地指出了这一点。
h
hatef

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

?:$a ? $a : $b 的缩写。如果 $a 的计算结果为 TRUE,则此表达式的计算结果为 $a。

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

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


S
Supun Praneeth

对于初学者:

空合并运算符 (??)

除了 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 函数

三元运算符简写 (?:)

每个虚假的东西(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: ..

希望这可以帮助


S
Script47

向下滚动 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。


请不要考虑链接...它与链接的三元组一样难以阅读/理解
@MarkBaker 链式三元组很难理解,因为 PHP 破坏了三元组关联性。这不适用于合并运算符,恕我直言,链式合并是完全可以理解的。
我不同意。链接空合并是一个很棒的功能,如果您了解运算符,它不会让人难以阅读。它通常在 javascript 中使用,一旦人们在 PHP 中适应它,这个不使用链接的调用应该停止。链接三元组很难阅读,但空合并很容易。当您从左到右阅读时,它只会列出接下来应该使用的值。
这看起来很像 JS 中常见的 a || b || c 模式,除了 PHP 可用于布尔值(JS 中的 false || 2 为 2;PHP 中的 false ?? 2 为 false)
我不同意你和其他人关于不使用链接的观点。这就像说永远不要使用 for 循环,因为可能不理解它们。开发人员/编码人员可以完全自由地使用他们理解的编码标准和实践,即使其他人不理解。就个人而言,我认为链式合并与 switch 语句非常相似。它返回找到(设置)的第一个值,如果没有找到则返回最后一个值。
Y
Yaron U.

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

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

尽管

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

主要区别在于左运算符是:

一个不为空的假值(0、''、false、[]、...)

未定义的变量


在上述 ?? 的扩展中不应有 $a =$a ?? 'fallback'设置或更改 $a 的值。 (它只返回一个值)。
D
Damian Green

使用 ???: 似乎各有利弊。使用 ?: 的优点是它评估 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...


你可以使用 $var = $false ??空?:“字符串为空/假/空/未定义”;
哇... ?? null ?: 的东西非常棒,谢谢先生。聪明的家伙。
Č
Čamo
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.

P
Pranav Rana

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


isset($_POST['fullname']) 已检查 NULL 值 - 所以第一个示例中的 && !is_null($_POST['fullname']) 无论如何都是多余的
A
Alexander Behling

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

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

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

因此,当使用 $_GET 甚至 $_REQUEST 时,您应该使用三元运算符,如下所示:

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

现在 $username 的值正如预期的那样是 'nobody' 。


接得好。此外,如果字符串为空,coalescing-operator 也会失败。
S
St3an

实用的简短回答:

尝试:

var_dump('' ?: 'ok');

对比

var_dump('' ?? 'ok');

如果测试值(或变量 *评估为 false,第一个将返回 'ok'

然而

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

*注意:如果你想用 ?: 测试一个变量,你必须首先确保它被初始化/设置,否则 PHP 会产生一个 E_NOTICE(而 ?? 不会)。