PHP 삼항 연산자 대 null 병합 연산자


342

PHP에서 삼항 연산자 속기 ( ?:)와 null 병합 연산자 ( ??) 의 차이점을 설명 할 수 있습니까 ?

그것들은 언제 다르게 행동하고 언제 똑같은 방식으로 (그런 경우에도)?

$a ?: $b

VS.

$a ?? $b

답변:


345

첫 번째 인수가 null 인 E_NOTICE경우, 정의되지 않은 변수가있을 때 null 병합이 a를 출력하지 않는다는 점을 제외하고는 기본적으로 동일 합니다. PHP 7.0 마이그레이션 문서는 이 말을했다 :

null 통합 연산자 (??)는 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";

통지가있는 줄은 null 통합 연산자와 달리 짧은 삼항 연산자를 사용하는 줄입니다. 그러나 공지 사항이 있더라도 PHP는 동일한 응답을 다시 제공합니다.

코드를 실행하십시오 : https://3v4l.org/McavC

물론 이것은 항상 첫 번째 인수가이라고 가정합니다 null. 더 이상 null이 아니면 ??연산자는 항상 첫 번째 인수를 반환하지만 ?:단축은 첫 번째 인수가 진실 인 경우에만 PHP가 항목을 부울 형으로 캐스팅 하는 방법에 의존한다는 점에서 차이점이 있습니다.

그래서:

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

다음 것 $a같을 수 false$b같음 'g'.


8
팁 : 사용중인 경우 ?? 대신? : 그러나 코드가 7 이전의 PHP 버전 (예 : 플러그인의 경우)과 호환되도록해야하는 경우,“? isset ($ something)? $ something : 코드 어디에서나 $ something_else 찾기 / 바꾸기 도구를 사용하여 정규식 옵션을 선택하고 찾기 필드에 삽입하는 메모장 ++ 또는 nedit (및 기타 편집기)에서도 쉽게 수행 할 수 있습니다. "\ s * (\ S +) \ s * \? \?" 그리고 교체 필드에서 : "isset ($ 1)? $ 1 :"따옴표없이 (nedit는 $ 1 대신 \ 1을 사용합니다). 그런 다음 모두 교체하십시오.
Damian Green

14
이것이 정답이지만 진실성 점검은 가장 큰 차이이며 더욱 강조되어야합니다.
mancze

2
@MasterOdin 답변이 마음에 들지 않습니다. 둘 다 동일하지 않습니다. 다른 결과가 있습니다.
호기심

1
사용할 수 있다는 점은 주목할 가치가 있습니까 ?? 체인으로. 예를 들면 다음 $b = []; var_dump($b['a']['b']['c'] ?? 'default');과 같습니다.$b = new Foo; var_dump($b->a()->b()->c() ?? 'default');
Jack 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
  • 0, empty string, NULL, false, !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. 널 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';

    멋지죠? :-)


3
지금까지 가장 좋은 답변
Faizan Anwer Ali Rupani

69

다음과 같이 바로 가기 삼항 연산자를 사용하면 $_GET['username']설정되지 않은 경우 알림이 표시됩니다 .

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

따라서 대신 다음과 같이해야합니다.

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

널 병합 연산자는 위의 진술에 해당하며, 경우 '기본'을 반환합니다 $_GET['username']설정되지 않았거나 null:

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

참고 가 truthiness를 확인하지 않습니다 . 설정되어 있고 null이 아닌 경우에만 확인합니다.

이 작업을 수행 할 수도 있으며 첫 번째로 정의 된 (set 및 not null) 값이 반환됩니다.

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

이제는 적절한 통합 연산자입니다.


42

가장 큰 차이점은

  1. 삼항 연산자 표현식 expr1 ?: expr3은 평가 되지만 리턴되는 expr1경우 Null Coalescing Operator 표현식 은 그렇지 않은 경우 평가expr1TRUE(expr1) ?? (expr2)expr1expr1 NULL

  2. 삼항 연산자는 expr1 ?: expr3 왼쪽 값이 경우 통지를 방출 (expr1) 은 존재하지 않고 반면에 널 합체 운영자 (expr1) ?? (expr2) 왼쪽 값이 경우 특히, 통지를 방출하지 않는 (expr1) 것처럼 존재하지 않습니다 isset().

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

널 병합 연산자 (??)

$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로 취급하지만 단축 삼항 연산자는 그렇지 않습니다. 그리고 그것은 염두에 두어야 할 것입니다.

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

12

둘 다 더 긴 표현을위한 속기입니다.

?:의 약자입니다 $a ? $a : $b. $ a가 TRUE 로 평가되면이 표현식은 $ a로 평가됩니다 .

??의 약자입니다 isset($a) ? $a : $b. $ a가 설정되고 널이 아닌 경우이 표현식은 $ a로 평가됩니다.

$ a가 정의되지 않았거나 null 인 경우 사용 사례가 겹칩니다. $ a가 정의되지 ??않으면 E_NOTICE가 생성 되지 않지만 결과는 같습니다. $ a가 null이면 결과는 같습니다.


5

초보자를위한 :

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기능 과 유사

삼항 연산자 속기 (? :)

모든 잘못된 일들이 ( false, null, 0, 빈 문자열) 허위로 제공되지만, 그것은이 정의되지 않은 경우는 거짓으로 올하지만 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이 아닌 경우 첫 번째 피연산자를 리턴합니다. 그렇지 않으면 두 번째 피연산자를 반환합니다.

기본적으로 통합 연산자를 사용하면 삼항 연산자와 달리 null을 자동으로 확인하게됩니다.


1
연쇄를 고려하지 마십시오 ... 연쇄 삼항만큼 읽기 / 이해하기가 어렵습니다
Mark Baker

7
@MarkBaker Chained 삼진은 PHP가 삼진 연관성을 깨뜨려 이해하기 어렵습니다. 이것은 통합 연산자에는 적용되지 않으며 imho 연결 통합은 완벽하게 이해할 수 있습니다.
NikiC

7
동의하지 않습니다. null 병합을 연결하는 것은 훌륭한 기능이며 연산자를 이해하더라도 읽기가 어렵지 않습니다. 그것은 일반적으로 자바 스크립트에서 사용되며 일단 사람들이 PHP에서 익숙해지면 체인을 사용하지 않는 호출이 중지되어야합니다. 삼항 연결은 읽기가 매우 어렵지만 null 병합은 쉽습니다. 왼쪽에서 오른쪽으로 읽으면 다음에 사용해야 할 값이 나열됩니다.
earl3s

2
이것은 a || b || c부울에 사용할 수있는 PHP를 제외하고 JS 의 일반적인 패턴 과 매우 유사합니다 ( false || 2JS는 2, false ?? 2PHP는 false)
fregante

1
체인을 사용하지 않는 것에 대해서는 귀하 및 다른 사람들과 동의하지 않습니다. 루프를 이해하지 못할 수 있으므로 for 루프를 사용하지 마십시오. 개발자 / 코더는 다른 사람이 모르더라도 이해하는 코딩 표준 및 방법을 완벽하게 사용할 수 있습니다. 개인적으로 체인 연결을 스위치 설명과 매우 유사하다고 생각합니다. 발견 된 (설정된) 첫 번째 값을 찾지 못하면 마지막 값을 리턴합니다.
kurdtpage

3

다른 답변은 깊이 들어가서 훌륭한 설명을 제공합니다. 빠른 답변을 원하는 사람들에게는

$a ?: 'fallback' 이다 $a ? $a : 'fallback'

동안

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


가장 큰 차이점은 왼쪽 연산자가 다음 중 하나 일 때입니다.

  • 널 (null)이 아닌 falsy 값 ( 0, '', false, [], ...)
  • 정의되지 않은 변수

$a =위의 확장 에는 없어야합니다 ??. $ a의 값을 설정하거나 변경 $a ?? 'fallback' 하지 않습니다 . (단지 값을 반환합니다).
하긴

2

이 중 하나를 사용하는 장점과 단점이 있습니다 것 ??또는 ?:. 사용하는 전문가 ?:는 false와 null을 평가하고 ""를 동일하게 평가한다는 것입니다. 앞의 인수가 널이면 E_NOTICE를보고한다는 것이 단점입니다. 로 ??프로 더 E_NOTICE가 없다는 것입니다,하지만 죄수는 같은 거짓과 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: ---

그러나 삼항 연산자를 정교화함으로써 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를 발생시키지 않습니다.


3
$ var = $ false ??를 사용할 수 있습니까 ?? null? : "문자열이 비어 있거나 / false / null / 정의되지 않았습니다";
RedSparr0w

우와 ... ?? null ?:그거 정말 대단해요, 고마워요 영리한 사람.
Blaine Lafreniere

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 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 operator약어입니다 if-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'])첫 번째 예에서 중복 어쨌든입니다
Yaron U.

0

$ _GET 또는 $ _REQUEST와 같은 슈퍼 글로벌을 사용하는 경우 빈 문자열 일 수 있음을 알고 있어야합니다. 이 specal 경우이 예제는

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

$ username의 값이 이제 빈 문자열이므로 실패합니다.

따라서 $ _GET 또는 $ _REQUEST를 사용할 때는 다음과 같이 삼항 연산자를 사용해야합니다.

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

이제 $ username의 값은 'nobody'입니다.


잘 잡았습니다. 또한 빈 문자열의 경우 통합 연산자도 실패합니다.
Choxx
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.