PHP 개발자들이 자주 쓰는 삼항 연산자(ternary operator)는 사실 꽤 장황하고 읽기 어렵다. 특히 변수가 null인지 확인하고 기본값을 할당할 때마다 isset() ? $var : $default 같은 코드를 반복하면서 코드가 금방 복잡해진다. 다만 PHP 7.0 이상에서 제공하는 Null Coalescing Operator(??)와 Spaceship Operator(<=>)를 정확히 이해하고 활용하는 개발자는 많지 않다. 이번에는 이 두 연산자가 정확히 뭔지, 왜 필요한지, 어떻게 쓰는지 실무 예제와 함께 완벽하게 정리해서 소개하겠다.
Null Coalescing Operator(??)는 변수가 null인지 확인하고 null이면 다른 값을 사용하도록 하는 간단한 문법이다. isset()과 비슷하지만 훨씬 간결하다.
기본 문법:
$result = $variable ?? $default;
이것은 다음과 같이 작동한다:
- $variable이 null이 아니면 → $variable 반환
- $variable이 null이면 → $default 반환
- $variable이 정의되지 않았으면 → $default 반환 (Notice 에러 없음)
✗ 이전 방식 (장황함):
$user_name = isset($_GET['name']) ? $_GET['name'] : 'Guest';
$email = isset($userData['email']) ? $userData['email'] : 'no-email@example.com';
✓ Null Coalescing Operator 사용:
$user_name = $_GET['name'] ?? 'Guest';
$email = $userData['email'] ?? 'no-email@example.com';
결과 및 이점:
- 코드가 35% 더 짧다
- 읽기 쉽고 의도가 명확하다
- Notice 에러가 발생하지 않는다 (정의되지 않은 변수 접근 안전)
여러 개의 기본값을 순차적으로 확인해야 할 때 ?? 를 연쇄적으로 사용할 수 있다.
✓ 올바른 사용:
$config = [
'host' => null,
'user' => 'admin'
];
// 여러 대체값 중 첫 번째 null이 아닌 값 선택
$hostname = $config['host'] ?? $config['user'] ?? 'localhost';
// 결과: 'admin' (host는 null, user는 'admin'이므로)
$port = $config['port'] ?? $_ENV['DB_PORT'] ?? 3306;
// 결과: 3306 (모두 null이므로 기본값)
결과 및 활용:
- 설정값 우선순위를 명확하게 표현
- 여러 소스(배열, 환경변수, 기본값)에서 순차적으로 확인
- if 블록 없이 한 줄로 처리
Spaceship Operator(<=>)는 두 값을 비교해서 대소 관계를 정수로 반환한다. 정렬이나 대소 비교가 필요할 때 매우 유용하다.
기본 문법과 반환값:
$a <=> $b
// 반환값:
// -1 : $a < $b (a가 더 작음)
// 0 : $a == $b (같음)
// 1 : $a > $b (a가 더 큼)
✗ 이전 방식 (복잡함):
function compare_numbers($a, $b) {
if ($a < $b) {
return -1;
} elseif ($a == $b) {
return 0;
} else {
return 1;
}
}
$result = compare_numbers(5, 10); // -1
✓ Spaceship Operator 사용:
$result = 5 <=> 10; // -1
$result = 5 <=> 5; // 0
$result = 10 <=> 5; // 1
Spaceship Operator의 진정한 가치는 usort() 같은 커스텀 정렬 함수에서 나타난다.
✗ 이전 방식 (복잡한 콜백):
$users = [
['name' => 'Alice', 'age' => 25],
['name' => 'Bob', 'age' => 20],
['name' => 'Charlie', 'age' => 30]
];
usort($users, function($a, $b) {
if ($a['age'] < $b['age']) {
return -1;
} elseif ($a['age'] == $b['age']) {
return 0;
} else {
return 1;
}
});
✓ Spaceship Operator 사용:
$users = [
['name' => 'Alice', 'age' => 25],
['name' => 'Bob', 'age' => 20],
['name' => 'Charlie', 'age' => 30]
];
usort($users, function($a, $b) {
return $a['age'] <=> $b['age'];
});
// 결과 (나이 순 정렬):
// Bob (20), Alice (25), Charlie (30)
여러 기준으로 정렬 (다중 조건):
// 부서로 먼저 정렬, 같은 부서면 나이로 정렬
usort($employees, function($a, $b) {
$dept_cmp = $a['department'] <=> $b['department'];
return $dept_cmp !== 0 ? $dept_cmp : $a['age'] <=> $b['age'];
});
실무에서 자주 마주치는 API 응답 처리 코드를 개선해보자.
✗ 이전 방식:
$api_response = [
'status' => 'success',
'data' => [
'user' => null,
'timestamp' => null
]
];
// 방어적 프로그래밍이 복잡함
$user_id = isset($api_response['data']['user']['id']) ? $api_response['data']['user']['id'] : 'unknown';
$created_at = isset($api_response['data']['timestamp']) ? $api_response['data']['timestamp'] : date('Y-m-d H:i:s');
$api_status = isset($api_response['status']) ? $api_response['status'] : 'pending';
✓ Null Coalescing으로 개선:
$api_response = [
'status' => 'success',
'data' => [
'user' => null,
'timestamp' => null
]
];
$user_id = $api_response['data']['user']['id'] ?? 'unknown';
$created_at = $api_response['data']['timestamp'] ?? date('Y-m-d H:i:s');
$api_status = $api_response['status'] ?? 'pending';
결과 및 장점:
- 코드 길이 50% 단축
- null 체크 로직이 명확
- Notice 경고 없음
| 상황 | ✗ 잘못된 것 | ✓ 올바른 것 |
|---|---|---|
| null vs false 구분 | $flag = $config['enabled'] ?? true;(false면 true로 설정됨) | $flag = isset($config['enabled']) ? $config['enabled'] : true;(false 값을 보존) |
| 배열 키 확인 | $value = $arr['key'] ?? 'default';(E_NOTICE 발생 가능) | $value = $arr['key'] ?? 'default';(PHP 7.0+에서는 안전) |
| Spaceship으로 존재 확인 | if ($a <=> $b) { }(0은 false이므로 오류) | if (($a <=> $b) !== 0) { }(결과가 0이 아니면) |
Null Coalescing Operator(??)와 Spaceship Operator(<=>)는 PHP 7.0 이상에서 제공되는 강력한 도구다. 단순히 문법을 줄이는 것이 아니라 코드의 의도를 명확하게 표현하고 버그를 줄일 수 있다는 점이 핵심이다. 이 두 연산자를 습관적으로 사용하면, 가독성 높은 PHP 코드를 자연스럽게 작성할 수 있을 것이다. 지금 진행 중인 프로젝트에서 삼항 연산자나 복잡한 비교 로직을 찾아 이 글의 예제로 리팩토링해보면, 코드 품질의 눈에 띄는 향상을 체감할 수 있을 것이다.