PHP의 ?? 오퍼레이터

아주 오래전이지만, PHP 7.0에 ?? (null coalescing operator)가 추가되었습니다.

?? 오퍼레이터는 앞 오퍼랜드가 <unset 또는 null>이면 뒤 오퍼랜드를 반환하는 2항 연산자로,

isset()과 연관된 3항연산자 사용을 줄여주는 syntactic sugar입니다.

아래 코드는 기본적인 사용법입니다.

// 의도: $_GET['name']이 세트되지 않은 경우 'nobody'를 사용
$name = isset($_GET['name']) ? $_GET['name'] : 'nobody';
$name = $_GET['name']
?? 'nobody';

두 줄의 기능은 거의 같지만 ?? 덕분에 타이핑도 줄여주고 읽기도 쉬워졌습니다.

하지만 이 오퍼레이터를 사용해 <unset 또는 null>이 아닌 <unset 또는 falsy한 값>을 대체하려면 주의가 필요합니다.

예를 들어, $_GET['name']에 빈 스트링이 들어있을 때 'nobody'를 대입하려면 어떻게 해야 할까요?

$_GET['name'] = ''; // 주의: unset 일 수 있음
$name = $_GET['name']
?? 'nobody';
// $name ===
''

빈 스트링('')은 <unset 또는 null>이 아니므로 ??는 빈 스트링을 반환했습니다.

unset 상태일 가능성 때문에 여전히 ?? 오퍼레이터 사용을 피할 수 없습니다.

이런 경우를 간결하게 처리하려면 어떻게 해야 할까요?

뒤에 ?: 오퍼레이터를 추가해보겠습니다.

$_GET['name'] = ''; // 주의: unset 일 수 있음
$name = $_GET['name']
?? 'nobody' ?: 'nobody';
// $name === 'nobody'

?? 와 ?:를 함께 사용해서 원하는 결과가 나오는 것을 확인했습니다.

항상 이런 결과가 나오려면 언어 수준에서 항상 ??가 ?:보다 먼저 작동해야 하는데 과연 그럴까요?

PHP 홈페이지의 오퍼레이터 우선순위(operator precedence)를 보니

다행히 ?? 가 ?: 보다 앞서있는 걸로 나옵니다.

PHP 언어 디자이너가 이런 디테일한 작동을 고려해서 ??와 ?:의 순서를 정했는지 알 수는 없지만

다행히 <unset 또는 falsy> 처리의 간결한 표현 가능하고 안심하고 사용할 수 있겠습니다.

어쩌면 언젠가는 ??: 오퍼레이터가 나올지도 모르겠습니다.