PHP 8 이상에서 갑자기 나타나는 "Trying to access array offset on value of type null" 경고를 봤을까? 구 버전에서는 아무 문제 없던 코드가 업그레이드 후 작동을 멈춘다. 다만 대부분의 개발자들은 이 에러가 정확히 뭘 의미하는지, 왜 갑자기 뜨는지, 어떻게 고쳐야 하는지 혼란스러워한다. 이번에는 이 에러의 정확한 원인, PHP 버전별 동작 차이, 그리고 실전에서 써먹을 수 있는 완벽한 해결책을 정리해서 소개하겠다.
PHP 8 이전에는 null 값에 배열 인덱스로 접근해도 경고 없이 null을 반환했다. 하지만 PHP 8부터는 이런 "위험한 동작"을 명시적으로 경고한다. 쉽게 말해서, 존재하지 않을 수 있는 데이터를 마치 배열인 것처럼 접근하는 건 버그의 신호라는 뜻이다.
✗ 잘못된 코드 (PHP 8에서 경고 발생):
<?php
$user = null; // 예: 데이터베이스 조회 결과 없음
echo $user['name']; // Warning: Trying to access array offset on value of type null
?>
또는 함수가 null을 반환할 때:
<?php
function getUserData() {
// 조건에 따라 배열 또는 null 반환
return null;
}
$result = getUserData();
echo $result['email']; // Warning: Trying to access array offset on value of type null
?>
✓ 올바른 코드:
<?php
$user = getUserFromDB(1);
if ($user !== null) {
echo $user['name'];
} else {
echo 'User not found';
}
?>
장점: 의도가 명확하고 버그를 쉽게 발견할 수 있다. 단점: 코드가 길어진다.
✓ 올바른 코드:
<?php
$user = getUserFromDB(1);
if (isset($user['name'])) {
echo $user['name'];
} else {
echo 'Name not available';
}
?>
동작: null이거나 인덱스가 없으면 false를 반환한다. 가장 실무에서 자주 쓰인다.
✓ 올바른 코드:
<?php
$user = getUserFromDB(1);
// 한 줄로 처리: null이면 기본값 반환
echo $user['name'] ?? 'Unknown';
// 중첩된 배열도 안전하게
echo $user['profile']['bio'] ?? 'No bio';
?>
장점: 간결하고 기본값 설정이 쉽다. 이것이 현대 PHP의 표준이다.
✓ 올바른 코드:
<?php
function getUserData($id) {
// null이 아니라 빈 배열 반환
$user = $db->query("SELECT * FROM users WHERE id = ?", [$id]);
return $user ?: []; // null이면 빈 배열 반환
}
$user = getUserData(1);
echo $user['name'] ?? 'Not found'; // 항상 안전
?>
장점: 함수 호출부에서 매번 체크할 필요가 없다. 설계 단계에서 문제를 해결한다.
✓ 올바른 코드:
<?php
// 함수가 절대 null을 반환하지 않도록 보장
function getUserData($id): array {
$user = $db->query("SELECT * FROM users WHERE id = ?", [$id]);
return $user ?? []; // 타입이 맞지 않으면 TypeError 발생
}
$user = getUserData(1);
echo $user['name']; // 이제 안전함
?>
장점: IDE 자동완성이 정확해지고, 타입 불일치를 컴파일 단계에서 잡는다.
API에서 받은 JSON 데이터를 처리할 때 이 에러가 자주 발생한다:
✗ 잘못된 코드:
<?php
$response = json_decode($apiData, true); // null일 수 있음
echo $response['user']['email']; // 에러 위험
?>
✓ 올바른 코드 (추천):
<?php
$response = json_decode($apiData, true);
// 방법 A: 단계별 체크
if (!$response || !isset($response['user']) || !isset($response['user']['email'])) {
throw new Exception('Invalid API response');
}
echo $response['user']['email'];
// 방법 B: Null Coalescing 연산자 (더 간결)
$email = $response['user']['email'] ?? null;
if ($email === null) {
throw new Exception('Email not found in API response');
}
echo $email;
// 방법 C: 헬퍼 함수로 깔끔하게
function getNestedValue($array, $path, $default = null) {
$keys = explode('.', $path);
$value = $array;
foreach ($keys as $key) {
if (!is_array($value) || !isset($value[$key])) {
return $default;
}
$value = $value[$key];
}
return $value;
}
$email = getNestedValue($response, 'user.email', 'no-email@example.com');
echo $email; // 안전함
?>
| 실수 | 문제 | 올바른 방법 |
|---|---|---|
| ✗ empty($array['key']) | 0이나 빈 문자열도 false 처리됨 | ✓ isset($array['key']) 또는 array_key_exists() |
| ✗ @$array['key'] (@ 억제) | 에러만 숨길 뿐 실제 문제 해결 안 됨 | ✓ isset() 또는 ?? 연산자로 명시적으로 |
| ✗ (array)$data 강제 캐스팅 | 타입이 섞여서 더 복잡해짐 | ✓ is_array() 체크 후 접근 |
| ✗ if ($array) 존재 체크 | 빈 배열도 false이므로 부정확 | ✓ isset() 또는 array_key_exists() |
같은 코드라도 버전에 따라 다르게 처리된다:
| PHP 버전 | 동작 | 에러/경고 |
|---|---|---|
| PHP 7.0 이하 | null['key'] → null 반환 | 경고 없음 (위험) |
| PHP 7.1~7.4 | null['key'] → null 반환 | Notice: Trying to access offset on value of type null |
| PHP 8.0+ | null['key'] → null 반환 | Warning: Trying to access array offset on value of type null |
"Trying to access array offset on value of type null"은 PHP 8이 개발자의 부주의를 잡아내려는 신호다. 이 에러는 코드의 약한 부분을 드러내고, 버그가 프로덕션에 가기 전에 발견하도록 도와준다. 단순히 경고를 무시하거나 @ 기호로 억제하는 것이 아니라, isset()이나 ?? 연산자로 명시적으로 처리하는 습관이 모여서 견고한 코드를 만든다는 점을 잊지 말자. 이 글의 "방법 3: Null Coalescing 연산자"를 기본으로 삼고, 함수 반환값에 타입 힌트를 추가하면, 앞으로 이런 에러에서 자유로워질 것이다.