PHPの三項演算子とnullの合体演算子


341

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

彼らはいつ異なった振る舞いをし、いつ同じように振る舞いますか?

$a ?: $b

対。

$a ?? $b

回答:


344

最初の引数がnullの場合、それらは基本的に同じE_NOTICEですが、未定義の変数がある場合、nullの合体はを出力しません。PHP 7.0の移行ドキュメントは、これは言っています:

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

これを示すためのコード例を以下に示します。

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

通知がある行は、nullの合体演算子ではなく、省略形の三項演算子を使用している行です。ただし、通知があっても、PHPは同じ応答を返します。

コードを実行:https : //3v4l.org/McavC

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

そう:

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

次に、$aと等しく、false$b等しくなければなりません'g'


8
ヒント:を使用している場合は?? ?:の代わりに、コードを7より前のバージョンのPHPと互換性を持たせる必要があることに気づいた場合(exのプラグインの場合)、?? isset($ something)?$ something:コードのどこにでも$ something_else。これは、Notepad ++またはnedit(およびその他のエディター)で、検索/置換ツールを使用して正規表現オプションを選択し、検索フィールドに挿入することで簡単に行うことができます: "\ s *(\ S +)\ s * \?\?" 置換フィールド: "isset($ 1)?$ 1:"引用符なし(neditは$ 1の代わりに\ 1を使用します)。その後、すべてを交換してください。
Damian Green

14
これは正しい答えですが、真実性のチェックは大きな違いであり、さらに強調する必要があります。
mancze 2017

2
@MasterOdinあなたの答えに満足していません。どちらも同じではありません。結果が異なります。
好奇心旺盛な

1
あなたが使用できることは注目に値しますか?連鎖あり。例:$b = []; var_dump($b['a']['b']['c'] ?? 'default');またはオブジェクト付き$b = new Foo; var_dump($b->a()->b()->c() ?? 'default');
ジャックB

でも動作が異なりますのでご注意ください$a = [];。参照:3v4l.org/iCCa0
Soullivaneuh

75

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
  • これ??は同じです( !isset() || is_null() )

2.三項演算子- ?:

  • ?:anything falsy通過する門のようなものです。NULL
  • 0empty stringNULLfalse!isset()empty()... falsyにおいが何かを
  • 古典的な三項演算子のように: echo ($x ? $x : false)
  • 注:未定義の(または)変数?:をスローPHP NOTICEしますunset!isset()

3.それで、ドクター、私はいつ使用???:ますか?

  • 私は冗談です-私は医者ではありません、そしてこれは単なる解釈です
  • いつ使う?:
    • やってempty($x)チェックを
    • のような古典的な三項演算は!empty($x) ? $x : $y$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($user_name){
          $name = $user_name;
       }else {
          $name = 'anonymous';
       }
    } else { 
       $name = $_GET['name'];
    }

    これに:

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

    かっこいいですよね?:-)



69

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

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

だから代わりにあなたはこのようなことをしなければなりません:

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

演算子を合体ヌルは、上記のステートメントに相当し、あれば「デフォルト」を返します。$_GET['username']設定されていないかでありますnull

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

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

これを行うこともでき、最初に定義された(設定されているnull)値が返されます。

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

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


42

主な違いは

  1. 三項演算子の表現 expr1 ?: expr3を返すexpr1場合expr1に評価 TRUE反面ヌル合体オペレータ表現 (expr1) ?? (expr2) 評価さがにexpr1ている場合がexpr1ありません NULL

  2. 3項演算子 expr1 ?: expr3は、左側の値(expr1) が存在しない場合に通知を発行し ますが、一方で、Null結合演算子(expr1) ?? (expr2)特に、左側の値(expr1) が存在しない場合、通知を発行しませんisset()

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

ここでの違いと類似性を説明した表である'??'とは、?:

ここに画像の説明を入力してください

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


15

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

変数が空( '')の場合、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


これは、空の文字列が通常falseと見なされるPHPにとって、明らかに直感に反しています。しかし、それは??:のドキュメントに明確に示されていますIt returns its first operand if it exists and is not NULL; otherwise it returns its second operand
サイモン・

12

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

?:の略です$a ? $a : $b。$ aがTRUEと評価された場合、この式は$ aと評価されます。

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

$ aが未定義またはnullの場合、それらの使用例は重複します。$ aが未定義の場合??、E_NOTICEは生成されませんが、結果は同じです。$ aがnullの場合、結果は同じです。


5

初心者向け:

ヌル合体演算子(??)

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

お役に立てれば


4

このリンクを下にスクロールしてセクションを表示すると、以下のような比較例が表示されます。

<?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でない場合は、最初のオペランドを返します。それ以外の場合は、2番目のオペランドを返します。

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


1
チェーニングを考慮しないでください...チェーニングターナリと同様に読み取り/理解が困難です
Mark Ba​​ker

7
PHPが3項の連想性を破壊しているため、@ MarkBakerの3項連鎖は理解が困難です。これは合体演算子には適用されず、imho連鎖合体は完全に理解できます。
NikiC、2016年

7
同意しません。nullの合体を連鎖させることは優れた機能であり、演算子を理解していれば読みやすくなります。これは一般的にJavaScriptで使用され、人々がPHPでこれに慣れると、チェーンを使用しないこの呼び出しは停止します。3値の連鎖は非常に読みにくいですが、null結合は簡単です。左から右に読むと、次に使用する値がリストされているだけです。
Earl3s 2016

2
これはa || b || cJS の一般的なパターンに非常によく似ていますが、PHPをブール値に使用できる点が異なります(false || 2JSでは2 false ?? 2、PHPではfalse)
fregante

1
チェーニングを使用しないことについて、私はあなたや他の人々に同意しません。これは、ループを理解できない可能性があるため、ループに使用しないと言っているようなものです。開発者/コーダーは、他の人が理解していない場合でも、彼らが理解しているコーディング標準とプラクティスを完全に自由に使用できます。個人的には、連鎖合体はswitch文と非常に似ていると考えています。見つかった(設定された)最初の値を返し、何も見つからなかった場合は最後の値を返します。
kurdtpage 16

3

他の答えは深く入り、素晴らしい説明を与えます。簡単な答えを探している人のために、

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

ながら

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


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

  • NULLでないfalsy値(0''false[]、...)
  • 未定義の変数

$a =上記の展開には何もないはずです??。 $ aの値を設定または変更$a ?? 'fallback' しません。(単に値を返すだけです)。
Doin

2

??またはを使用することには長所と短所があるよう?:です。使用する利点?:は、falseとnullを評価し、 ""を同じに評価することです。欠点は、先行する引数がnullの場合、E_NOTICEを報告することです。??プロ何E_NOTICEがないことですが、conが、それは同じ偽とヌル評価しないということです。私の経験では、人々が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をスローせずに、falseまたは空の文字列 ""を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をスローしません...


3
$ var = $ falseを使用できますか?null?: "文字列が空/ false / null /未定義";
RedSparr0w 2017

おっと...それ?? null ?:はかなり素晴らしいです、ありがとうミスター。賢い男。
ブレインラフレニエール

1
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.

0

Null Coalescing operatorは、チェックwhether the variable is setとの2つのタスクのみを実行します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です。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.

したがって、2つの違いは、Null Coalescing operator演算子は未定義の変数をternary operator。よりも処理するように設計されていることです。一方、ternary operatorはの省略形ですif-else

Null Coalescing operatorternary operator、を置き換えるものではありませんが、上記の例のような一部のユースケースでは、手間をかけずにクリーンなコードを記述できます。

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


isset($_POST['fullname'])すでにNULL値をチェックしているため&& !is_null($_POST['fullname'])、最初の例ではとにかく冗長です
Yaron U.

0

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

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

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

したがって、$ _ GETまたは$ _REQUESTを使用する場合は、次のように代わりに三項演算子を使用する必要があります。

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

現在、$ usernameの値は期待どおり「nobody」です。


良いキャッチ。また、空の文字列の場合、coalescing-operatorも失敗します。
Choxx
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.