web-dev-qa-db-ja.com

PHP 三項演算子とNULL合体演算子

誰かがPHPで三項演算子の省略形(?:)とnull合体演算子(??)の違いを説明できますか?

彼らはいつ異なった振る舞いをしますか、そして同じようにします(それが起こるならば)?

$a ?: $b

VS.

$a ?? $b
233
balping

最初の引数がnullの場合は、未定義の変数があるときにnull合体がE_NOTICEを出力しないことを除いて、基本的に同じです。 PHP 7.0への移行に関するドキュメント

Isset()と組み合わせて3値を使用する必要があるという一般的な場合のための構文糖として、null合体演算子(??)が追加されました。最初のオペランドが存在し、それがNULLでない場合は、その最初のオペランドを返します。それ以外の場合は2番目のオペランドを返します。

これを実証するためのいくつかのサンプルコードがあります。

<?php

$a = null;

print $a ?? 'b';
print "\n";

print $a ?: 'b';
print "\n";

print $c ?? 'a';
print "\n";

print $c ?: 'a';
print "\n";

$b = array('a' => null);

print $b['a'] ?? 'd';
print "\n";

print $b['a'] ?: 'd';
print "\n";

print $b['c'] ?? 'e';
print "\n";

print $b['c'] ?: 'e';
print "\n";

そしてそれは出力です:

b
b
a

Notice: Undefined variable: c in /in/apAIb on line 14
a
d
d
e

Notice: Undefined index: c in /in/apAIb on line 33
e

この通知がある行は、null合体演算子とは対照的に、私が速記三元演算子を使用しているものです。ただし、通知があってもPHPは同じ応答を返します。

コードを実行します。 https://3v4l.org/McavC

もちろん、これは常に最初の引数がnullであると仮定しています。 nullでなくなると、??演算子は常に最初の引数を返すのに対し、?:の省略形は最初の引数が真の場合にのみ返されるという違いがあり、それは PHPブール値に型キャストします

そう:

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

$afalse$b'g'と等しくなります。

233
MasterOdin

このようにショートカットの三項演算子を使用した場合、$_GET['username']が設定されていないと通知が表示されます。

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

それで、代わりにあなたはこのようなことをしなければなりません:

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

null合体演算子 は上記のステートメントと同じで、$_GET['username']が設定されていないかnullである場合は 'default'を返します。

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

それは真実性をチェックしないことに注意してください 。設定されていてnullではない場合のみチェックします。

これを行うこともでき、最初の defined (setではなくnull)の値が返されます。

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

これが適切な合体演算子です。

59
Andrew

大きな違いは

  1. 三項演算子expression expr1 ?: expr3は、expr1TRUEに評価されるが、その反対の場合はexpr1を返しますNull Coalescing Operator expression (expr1) ?? (expr2)は、expr1notNULLの場合、expr1に評価されます。

  2. 三項演算子expr1 ?: expr3は、左側の値(expr1)が存在しないが、他方に通知がある場合Null Coalescing Operator(expr1) ?? (expr2)特に、isset()のように、左側の値(expr1)が存在しない場合は通知を発行しません。

  3. TernaryOperatorは連想的に残されます

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

    Null Coalescing Operatorは右結合です

    ($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 Coalescing Operator(??)

$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

特記事項:null合体演算子と三項演算子は式であり、変数ではなく式の結果として評価されること。これは、参照によって変数を返すかどうかを知ることが重要です。このステートメントは$ foo ??を返します。 $ bar;そして$ var == 42を返しますか? $ a:$ b;したがって、参照渡し関数では機能せず、警告が発行されます。

40
Dhairya Lakhera

Phpの対話モード(端末ではphp -a)で以下を実行してください。各行のコメントは結果を示しています。

var_dump (false ?? 'value2');   # bool(false)
var_dump (true  ?? 'value2');   # bool(true)
var_dump (null  ?? 'value2');   # string(6) "value2"
var_dump (''    ?? 'value2');   # string(0) ""
var_dump (0     ?? 'value2');   # int(0)

var_dump (false ?: 'value2');   # string(6) "value2"
var_dump (true  ?: 'value2');   # bool(true)
var_dump (null  ?: 'value2');   # string(6) "value2"
var_dump (''    ?: 'value2');   # string(6) "value2"
var_dump (0     ?: 'value2');   # string(6) "value2"

だから、これは私の解釈です:

1. NULL合体演算子 - ??

  • ??は、 を介してNULLを許可するだけの「ゲート」のようなものです。
  • したがって、常に最初のパラメータを返す最初のパラメータが偶然NULLでない限り。
  • これは??( !isset() || is_null() )と同じであることを意味します

2.三項演算子 - ?:

  • ?:anything falsyを通過させる門のようなものです - NULLを含む
  • 0empty stringNULLfalse!isset()empty() ..偽造の匂いがするもの
  • 古典的な三項演算子のように:echo ($x ? $x : false)
  • 注:?:は未定義(unsetまたは!isset())変数にPHP NOTICEを投げます

3.医者、いつ???:を使うのですか。

  • 私は冗談です - 私は医者ではありませんそしてこれはただの解釈です
  • の場合は?:を使用します。
    • empty($x)チェックをする
    • !empty($x) ? $x : $yのような古典的な3項演算は$x ?: $yに短縮できます
    • if(!$x) { fn($x); } else { fn($y); }fn(($x ?: $y))に短縮できます
  • の場合は??を使用します。
    • !isset() || is_null()チェックをしたい
    • たとえば、オブジェクトが存在するかどうかを確認します - $object = $object ?? new objClassName();

4.スタッキング演算子.

  1. 三項演算子をスタックすることができます ...

    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
    

    このコードの出典とクレジット

    これは基本的に次のシーケンスです。

    if( truthy ) {}
    else if(truthy ) {}
    else if(truthy ) {}
    ..
    else {}
    
  2. NULL Coalese演算子はスタックできます ...

    $v = $x ?? $y ?? $z; 
    

    これは次のシーケンスです。

    if(!isset($x) || is_null($x) ) {} 
    else if(!isset($y) || is_null($y) ) {}
    else {}
    
  3. スタッキングを使うと、これを短くすることができます:

    if(!isset($_GET['name'])){
       if(isset($user_name) && !empty($user_name)){
          $name = $user_name;
       }else {
          $name = 'anonymous';
       }
    } else { 
       $name = $_GET['name'];
    }
    

    これに:

    $name = $_GET['name'] ?? $user_name ?: 'anonymous';
    

    クールだよね? :-)

33
a20

動的データ処理に関しては、どちらも動作が異なります。

変数が空( '')の場合、null合体は変数をtrueとして扱いますが、省略形の3項演算子は扱いません。そしてそれは心に留めておくべきことです。

$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

12
Chazy Chaz

どちらも長い式の省略形です。

?:$a ? $a : $bの短縮形です。 $ aが _ true _ に評価されると、この式は$ aに評価されます。

??isset($a) ? $a : $bの短縮形です。 $ aが設定されていてnullでない場合、この式は$ aに評価されます。

それらのユースケースは、$ aが未定義またはnullの場合に重複します。 $ aが未定義の場合、??はE_NOTICEを生成しませんが、結果は同じです。 $ aがnullの場合、結果は同じです。

9
Dean Or

初心者向け:

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関数と同様

三項演算子の省略形(?:)

すべての偽物(falsenull0、empty string)はfalseになりますが、未定義の場合はfalseにもなりますが、Noticeはスローされます

ex

$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: ..

お役に立てれば

4
Supun Praneeth

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()と組み合わせて3値を使用する必要があるという一般的な場合のための構文糖として、null合体演算子(??)が追加されました。最初のオペランドが存在し、それがNULLでない場合は、その最初のオペランドを返します。それ以外の場合は2番目のオペランドを返します。

基本的に、合体演算子を使用すると、3項演算子とは異なり、自動的にnullをチェックします。

3
Script47

??または?:を使うことには賛否両論があるようです。 ?:を使用する利点は、falseとnullを評価し、同じことを意味します。前の引数がnullの場合は、E_NOTICEが報告されます。 ??を使えば、E_NOTICEがないという長所がありますが、欠点はfalseと同じ評価ではないことです。私の経験では、人々はnullとfalseを入れ替えて使い始めるのを見てきましたが、その後はnullまたはfalseのどちらか一方を使うのと一致するようにコードを修正することにしました。もう1つの方法は、より複雑な3値条件(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: ---

ただし、3項演算子について詳しく説明することで、e_noticeをスローせずに、偽または空の文字列 ""をnullのように動作させることができます。

$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をスローしません...

2
Damian Green

他の答えは深く入り、素晴らしい説明を与えます。クイックアンサーを探している人のために、

$a ?: 'fallback'$a ? $a : 'fallback'です

ながら

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


主な違いは、左演算子が次のいずれかである場合です。

  • Nullではない偽の値(0''false[]、...)
  • 未定義の変数
1
Yaron U.
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.
1
Čamo

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 operatorternary operatorを改良したものです。この2つを比較した次のコードスニペットを見てください。

<?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 operatorternary operatorを置き換えることを意図したものではありませんが、上記の例のようないくつかの使用例では、手間をかけずにきれいなコードを書くことができます。

クレジット: http://dwellupper.io/post/6/php7-null-coalescing-operator-usage-and-examples

0
Pranav Rana

$ _GETや$ _REQUESTのようなスーパーグローバルを使用するときは、それらが空文字列になる可能性があることに注意してください。この特別なケースでは、この例

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

$ usernameの値が空の文字列になったため、失敗します。

そのため、$ _GETや$ _REQUESTを使うときは、このように三項演算子を使うべきです。

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

$ usernameの値は、期待どおりに 'nobody'になりました。

0