배열에서 값이나 키를 찾을 때 어떤 함수를 쓸지 몰라서 헷갈린 경험이 있을까? 대부분의 PHP 개발자들은 습관적으로 in_array()를 사용하거나, 상황을 제대로 파악하지 못한 채 검색 결과에서 본 함수를 그냥 가져다 쓴다. 다만 각 함수의 차이를 정확히 모르면 성능 저하는 물론이고, 버그까지 야기할 수 있다. 이번에는 array_search(), in_array(), array_key_exists()의 정확한 차이, 언제 어떤 함수를 써야 하는지, 그리고 각각의 위험성을 완벽하게 정리해서 소개하겠다.

 

1단계. 세 함수의 기본 역할 이해하기

array_search(), in_array(), array_key_exists()는 각각 목적이 다르다. 먼저 각 함수가 뭘 하는 함수인지 이해하는 게 첫 번째다.

array_key_exists()는 배열에 특정 키가 존재하는지만 확인한다. 값이 뭔지는 상관없고, 키 자체의 존재 여부만 본다. 반환값은 true/false다.

in_array()는 배열에 특정 값이 있는지 찾는다. 하지만 키는 신경 쓰지 않는다. 값만 있으면 true를 반환한다.

array_search()는 배열에서 특정 값을 찾아서 그 값의 키를 반환한다. 값이 없으면 false를 반환한다. 쉽게 말해 in_array()의 키 반환 버전이다.

 

2단계. 코드로 차이 확인하기

직접 코드를 보면서 차이를 명확히 해보자.

$users = array(
    1 => 'Alice',
    2 => 'Bob',
    3 => 'Charlie'
);

// array_key_exists() - 키 존재 확인
if (array_key_exists(1, $users)) {
    echo "키 1이 존재함"; // 출력됨
}
if (array_key_exists(4, $users)) {
    echo "키 4가 존재함"; // 출력 안 됨
}

// in_array() - 값 존재 확인
if (in_array('Alice', $users)) {
    echo "Alice가 있음"; // 출력됨
}
if (in_array('Dave', $users)) {
    echo "Dave가 있음"; // 출력 안 됨
}

// array_search() - 값을 찾아서 키 반환
$key = array_search('Bob', $users);
if ($key !== false) {
    echo "Bob은 키 " . $key . "에 있음"; // 출력됨: Bob은 키 2에 있음
}

$key = array_search('Eve', $users);
if ($key === false) {
    echo "Eve는 없음"; // 출력됨
}

✓ 올바른 코드: array_search()는 키를 반환하므로 false와 반드시 ===로 비교해야 한다. 숫자 0이 키일 수 있기 때문이다.

 

3단계. 실전 예제로 적용해보기

이제 실무에서 각 함수를 언제 써야 하는지 구체적으로 살펴보자.

예제 1) 사용자 ID로 데이터 확인 - array_key_exists() 사용
// 사용자 정보 배열 (키가 사용자 ID)
$userData = array(
    101 => array('name' => 'Alice', 'email' => 'alice@example.com'),
    102 => array('name' => 'Bob', 'email' => 'bob@example.com'),
    103 => array('name' => 'Charlie', 'email' => 'charlie@example.com')
);

// ✗ 잘못된 코드
if (in_array('Alice', $userData)) { // 배열 값 전체를 검색하므로 느리고 비효율적
    // 이 조건은 작동하지 않음
}

// ✓ 올바른 코드
$userId = 101;
if (array_key_exists($userId, $userData)) {
    echo "사용자 " . $userData[$userId]['name'] . "이(가) 있음";
}
예제 2) 권한 목록에서 값 확인 - in_array() 사용
$allowedRoles = array('admin', 'editor', 'viewer');

// ✗ 잘못된 코드
if (array_key_exists('admin', $allowedRoles)) {
    // 이건 키를 찾는 거라 작동 안 함. 배열 키는 0, 1, 2인데 'admin'을 찾으려니까
}

// ✓ 올바른 코드
$userRole = $_SESSION['role'];
if (in_array($userRole, $allowedRoles)) {
    echo "권한이 있음";
}
예제 3) 상품 ID 찾기 - array_search() 사용
$products = array(
    'PROD001' => 'Laptop',
    'PROD002' => 'Monitor',
    'PROD003' => 'Keyboard'
);

// 상품명으로 상품 ID를 찾아야 할 때
$searchProduct = 'Monitor';

// ✗ 잘못된 코드
if (in_array($searchProduct, $products)) {
    // 상품은 찾았지만, ID는 뭔지 알 수 없음
    echo "상품이 있음";
}

// ✓ 올바른 코드
$productId = array_search($searchProduct, $products);
if ($productId !== false) {
    echo "상품 ID: " . $productId; // 출력: 상품 ID: PROD002
}

 

4단계. 주의사항과 흔한 실수
함정 1) array_search()와 0 키의 치명적 차이
$colors = array('red', 'green', 'blue');

// ✗ 잘못된 코드
if (array_search('red', $colors)) {
    echo "빨강이 있음";
} else {
    echo "빨강이 없음"; // 이게 출력됨! 키가 0이라 false로 판단됨
}

// ✓ 올바른 코드
if (array_search('red', $colors) !== false) {
    echo "빨강이 있음"; // 이제 제대로 출력됨
}
함정 2) in_array() 타입 비교 오류
$values = array(0, '1', '2', 3);

// ✗ 잘못된 코드 (느슨한 타입 비교)
if (in_array('0', $values)) {
    echo "'0'이 있음"; // 출력됨! 0 == '0'이므로
}

// ✓ 올바른 코드 (엄격한 타입 비교)
if (in_array('0', $values, true)) {
    echo "'0'이 있음"; // 출력 안 됨
}
함정 3) array_key_exists()는 null 값도 감지한다
$settings = array(
    'theme' => 'dark',
    'notification' => null
);

// ✗ 잘못된 코드 (isset 사용)
if (isset($settings['notification'])) {
    echo "알림 설정이 있음"; // 출력 안 됨. null은 isset에서 false
}

// ✓ 올바른 코드 (array_key_exists 사용)
if (array_key_exists('notification', $settings)) {
    echo "알림 설정 키가 있음"; // 출력됨. null이어도 키는 존재
}

 

5단계. 함수별 선택 기준 정리
상황 함수 반환값 예제
배열 키의 존재 여부만 확인 array_key_exists() true/false array_key_exists('id', $user)
배열 값의 존재 여부만 확인 in_array() true/false in_array('admin', $roles)
값을 찾아서 그 키를 알아야 함 array_search() 키 또는 false $key = array_search('Bob', $users)
null 값까지 포함해서 키 존재 확인 array_key_exists() true/false array_key_exists('setting', $config)
값이 있는지만 빠르게 확인 (타입 안 중요) in_array() true/false in_array($id, $allowedIds)

 

6단계. 성능 비교와 대규모 배열 처리

수천 개의 요소가 있는 배열에서는 함수 선택이 성능을 크게 좌우한다. array_key_exists()는 해시 테이블 조회라 O(1) 상수 시간이지만, in_array()와 array_search()는 선형 검색이므로 O(n) 시간이 걸린다. 즉 배열이 클수록 in_array() 사용이 느려진다.

대규모 데이터를 자주 검색해야 하면, 배열을 키 기반으로 재구성하거나 isset()을 써서 키 검색으로 전환하는 게 훨씬 빠르다.

// ✗ 느린 코드 (10,000개 아이디 검색)
$userIds = array(1, 2, 3, ..., 10000);
for ($i = 0; $i < 1000; $i++) {
    if (in_array($searchId, $userIds)) { // 매번 전체 배열 검색
        // ...
    }
}

// ✓빠른 코드 (키 기반 검색)
$userIds = array_flip(array(1, 2, 3, ..., 10000)); // 값과 키를 뒤집음
for ($i = 0; $i < 1000; $i++) {
    if (isset($userIds[$searchId])) { // O(1) 해시 조회
        // ...
    }
}

 

배열 검색 함수 선택은 단순해 보이지만 버그와 성능 문제의 원인이 될 수 있다. array_key_exists()는 키 존재, in_array()는 값 존재, array_search()는 값으로 키를 찾을 때 쓴다는 점을 명확히 해두자. 특히 array_search()의 0 키 함정과 in_array()의 타입 비교, array_key_exists()의 null 값 처리는 반드시 기억해두고, 대규모 배열은 isset() 기반 키 검색으로 성능을 확보하는 습관을 들이면 훨씬 안정적인 코드를 만들 수 있을 것이다.