배열을 다룰 때 여러 배열을 하나로 합치거나 키-값을 매핑해야 할 일이 자주 생긴다. 그런데 array_merge(), array_combine(), array_replace() 중 어떤 함수를 쓸지 정하지 못해 삽질하는 개발자가 많다. 각 함수가 겹치는 부분도 있고, 미묘한 차이가 있어서 상황에 맞지 않는 함수를 쓰면 예상 밖의 결과가 나온다. 이번에는 세 함수의 정확한 동작 방식, 언제 어떤 함수를 써야 하는지, 그리고 실무에서 자주 하는 실수까지 완벽하게 정리했다.

 

1단계. 세 함수의 기본 동작 방식 이해하기

array_merge()는 여러 배열을 연결해서 새로운 배열을 만든다. 숫자 키는 리셋되지만 문자 키는 뒤의 배열 값으로 덮어쓴다. array_combine()은 한 배열을 키로, 다른 배열을 값으로 사용해서 새 배열을 만든다. 두 배열의 길이가 정확히 같아야 한다. array_replace()는 첫 번째 배열을 기본으로 하고 뒤의 배열들로 값을 교체한다. 키가 없으면 추가되고, 있으면 덮어쓴다.

세 함수를 간단한 예시로 비교해보자.

함수 용도 숫자 키 처리 문자 키 처리 배열 길이
array_merge() 배열 연결 리셋됨 덮어씀 자유
array_combine() 키-값 매핑 해당없음 해당없음 반드시 같음
array_replace() 배열 교체 유지됨 덮어씀 자유

 

2단계. 각 함수의 상세 동작과 코드 예제

 

array_merge() - 배열 연결하기

array_merge()는 뒤의 배열이 앞의 배열을 덮어쓰는 것처럼 보이지만, 사실은 숫자 키가 완전히 리셋된다. 예를 들어 첫 번째 배열의 숫자 키가 0, 1, 2라면 두 번째 배열의 숫자 키도 리셋되어 다시 0부터 시작한다. 하지만 문자 키는 그렇지 않다. 문자 키가 중복되면 뒤의 배열 값으로 덮어쓴다.

// ✗ 잘못된 예: 숫자 키가 유지될 거라 기대
$arr1 = [10 => 'a', 20 => 'b'];
$arr2 = [30 => 'c', 40 => 'd'];
$result = array_merge($arr1, $arr2);
print_r($result);
// 예상: [10 => 'a', 20 => 'b', 30 => 'c', 40 => 'd']
// 실제: [0 => 'a', 1 => 'b', 2 => 'c', 3 => 'd']
// 숫자 키가 모두 리셋됨!
// ✓ 올바른 이해: 문자 키는 유지되고, 중복되면 덮어씀
$arr1 = ['name' => 'John', 'age' => 30];
$arr2 = ['age' => 31, 'city' => 'Seoul'];
$result = array_merge($arr1, $arr2);
print_r($result);
// 결과:
// Array ( [name] => John [age] => 31 [city] => Seoul )
// age 값이 30에서 31로 덮어써짐
// ✓ 실전 사용법: 여러 배열 한 번에 합치기
$configs = [
  ['debug' => true],
  ['timeout' => 30],
  ['retries' => 3]
];
$merged = array_merge(...$configs);
print_r($merged);
// 결과: Array ( [debug] => 1 [timeout] => 30 [retries] => 3 )

 

array_combine() - 키-값 매핑하기

array_combine()은 첫 번째 배열을 키로, 두 번째 배열을 값으로 사용한다. 두 배열의 요소 개수가 정확히 같아야 한다. 이 함수는 CSV 파일을 읽을 때 헤더 행을 키로 만들 때, 또는 데이터베이스 쿼리 결과를 연관 배열로 변환할 때 매우 유용하다.

// ✗ 잘못된 예: 배열 길이가 다를 때
$keys = ['name', 'age', 'city'];
$values = ['John', 30];  // 길이가 다름
$result = array_combine($keys, $values);
// Fatal error: Uncaught ValueError: array_combine(): Both parameters expected to have the same number of elements
// ✓ 올바른 사용: 배열 길이가 같을 때
$headers = ['name', 'email', 'phone'];
$data = ['John', 'john@example.com', '010-1234-5678'];
$result = array_combine($headers, $data);
print_r($result);
// 결과:
// Array ( [name] => John [email] => john@example.com [phone] => 010-1234-5678 )
// ✓ 실전 사용법: CSV 파일 읽기
$file = fopen('data.csv', 'r');
$header = fgetcsv($file);  // 첫 줄: ['id', 'name', 'age']
while ($row = fgetcsv($file)) {
  $record = array_combine($header, $row);  // 헤더를 키로, 데이터를 값으로
  echo $record['name'];  // 훨씬 읽기 편함
}
fclose($file);

 

array_replace() - 배열 값 교체하기

array_replace()는 첫 번째 배열을 기본으로 하고, 뒤의 배열들로 값을 교체한다. 중요한 점은 숫자 키도 유지된다는 것이다. 그래서 기본 설정 배열에 사용자 설정을 덮어쓸 때, 또는 데이터에 기본값을 적용할 때 자주 쓰인다.

// ✗ 잘못된 예: array_merge()로 기본값을 덮으려고 함
$defaults = [0 => 'red', 1 => 'blue', 2 => 'green'];
$user_colors = [0 => 'yellow'];  // 첫 번째만 변경하고 싶음
$result = array_merge($defaults, $user_colors);
print_r($result);
// 예상: [0 => 'yellow', 1 => 'blue', 2 => 'green']
// 실제: [0 => 'yellow', 1 => 'blue', 2 => 'green', 3 => 'green']
// 숫자 키가 리셋되어 순서가 뒤바뀜
// ✓ 올바른 방법: array_replace() 사용
$defaults = [0 => 'red', 1 => 'blue', 2 => 'green'];
$user_colors = [0 => 'yellow'];  // 첫 번째만 변경
$result = array_replace($defaults, $user_colors);
print_r($result);
// 결과: Array ( [0] => yellow [1] => blue [2] => green )
// 숫자 키가 유지되고 정확히 덮어써짐
// ✓ 실전 사용법: API 응답에 기본값 적용
$default_user = [
  'id' => 0,
  'name' => 'Unknown',
  'email' => 'unknown@example.com',
  'status' => 'inactive'
];

// API에서 받은 불완전한 데이터
$api_data = [
  'id' => 123,
  'name' => 'John',
  'status' => 'active'  // email은 없음
];

$user = array_replace($default_user, $api_data);
print_r($user);
// 결과:
// Array (
//   [id] => 123
//   [name] => John
//   [email] => unknown@example.com  // 기본값 유지
//   [status] => active
// )

 

3단계. 실전 예제로 상황별 함수 선택하기

 

상황 1. 데이터베이스 쿼리 결과에 기본값 적용
// 데이터베이스에서 일부 필드만 가져옴
$db_row = [
  'user_id' => 42,
  'username' => 'alice',
  'created_at' => '2024-01-15'
];

// 기본 스키마 정의
$schema = [
  'user_id' => 0,
  'username' => '',
  'email' => '',
  'created_at' => '',
  'updated_at' => '',
  'is_verified' => false
];

// array_replace()로 기본값 채우기
$complete_row = array_replace($schema, $db_row);
print_r($complete_row);
// 결과: user_id와 username은 DB 값, 나머지는 기본값

 

상황 2. 설정 파일 병합
// config/default.php
$default_config = [
  'db_host' => 'localhost',
  'db_port' => 3306,
  'db_user' => 'root',
  'db_pass' => '',
  'cache_ttl' => 3600,
  'debug' => false
];

// config/local.php
$local_config = [
  'db_host' => '192.168.1.100',
  'db_pass' => 'secret123',
  'debug' => true
];

// array_replace()로 로컬 설정만 덮어쓰기
$config = array_replace($default_config, $local_config);
print_r($config);
// 결과: 로컬 설정이 기본값을 덮고, 없는 항목은 기본값 유지

 

상황 3. 여러 필터를 배열로 합치기
// 검색 필터를 여러 단계에서 수집
$base_filter = ['status' => 'active'];
$user_filter = ['category' => 'products'];
$time_filter = ['created_after' => '2024-01-01'];

// array_merge()로 모두 합치기
$final_filter = array_merge($base_filter, $user_filter, $time_filter);
print_r($final_filter);
// 결과:
// Array (
//   [status] => active
//   [category] => products
//   [created_after] => 2024-01-01
// )

 

4단계. 주의사항과 흔한 실수

 

✗ 실수 1. array_merge()로 숫자 키를 유지하려고 함

array_merge()를 사용하면 숫자 키는 항상 0부터 리셋된다. 숫자 키를 유지하려면 + 연산자나 array_replace()를 써야 한다.

// ✗ 잘못된 방법
$arr1 = [5 => 'a', 10 => 'b'];
$arr2 = [15 => 'c'];
$result = array_merge($arr1, $arr2);
// [0 => 'a', 1 => 'b', 2 => 'c']

// ✓ 올바른 방법 1: + 연산자
$result = $arr1 + $arr2;
// [5 => 'a', 10 => 'b', 15 => 'c']

// ✓ 올바른 방법 2: array_replace()
$result = array_replace($arr1, $arr2);
// [5 => 'a', 10 => 'b', 15 => 'c']

 

✗ 실수 2. array_combine()으로 길이가 다른 배열 사용

array_combine()은 두 배열의 길이가 정확히 같아야 한다. 길이가 다르면 ValueError가 발생한다.

// ✗ 잘못된 방법
$keys = ['a', 'b', 'c'];
$values = ['1', '2'];  // 길이가 다름
$result = array_combine($keys, $values);
// ValueError: Both parameters expected to have the same number of elements

// ✓ 올바른 방법: 미리 길이 확인
if (count($keys) === count($values)) {
  $result = array_combine($keys, $values);
} else {
  // 길이 맞추기 또는 다른 방식 사용
  $values = array_pad($values, count($keys), null);
  $result = array_combine($keys, $values);
}

 

✗ 실수 3. 중첩 배열에서 array_merge() 사용

array_merge()는 1차원 배열만 제대로 병합한다. 중첩 배열의 경우 예상과 다른 결과가 나올 수 있다.

// ✗ 잘못된 예: 중첩 배열 병합
$arr1 = ['settings' => ['theme' => 'dark']];
$arr2 = ['settings' => ['lang' => 'ko']];
$result = array_merge($arr1, $arr2);
print_r($result);
// 결과: settings 배열이 완전히 덮어써짐
// Array ( [settings] => Array ( [lang] => ko ) )
// theme이 사라짐!

// ✓ 올바른 방법: 재귀적으로 병합
function array_merge_recursive_custom($arr1, $arr2) {
  foreach ($arr2 as $key => $value) {
    if (is_array($value) && isset($arr1[$key]) && is_array($arr1[$key])) {
      $arr1[$key] = array_merge_recursive_custom($arr1[$key], $value);
    } else {
      $arr1[$key] = $value;
    }
  }
  return $arr1;
}

$result = array_merge_recursive_custom($arr1, $arr2);
print_r($result);
// 결과: Array ( [settings] => Array ( [theme] => dark [lang] => ko ) )

 

5단계. 핵심 정리와 다음 단계

array_merge(), array_combine(), array_replace()는 배열을 다루는 실무에서 매일 마주치는 함수들이다. 세 함수를 정확히 이해하지 못하면 데이터 손실, 키 순서 꼬임, 예상 밖의 타입 변환 같은 버그가 발생한다. 핵심을 정리하면 이렇다.

array_merge()는 배열을 연결할 때만 쓴다. 숫자 키가 리셋된다는 점을 명심해야 한다. array_combine()은 두 배열을 키-값 쌍으로 변환하고 싶을 때, 특히 CSV나 데이터베이스 헤더 처리에서 유용하다. array_replace()는 기본값이 있고 사용자 입력으로 덮어쓸 때, 즉 설정 파일이나 API 응답 처리에 최적이다.

이 글의 상황별 예제와 주의사항을 참고해서 상황에 맞는 함수를 선택하면, 배열 조작으로 인한 데이터 손실과 버그를 크게 줄일 수 있을 것이다. 특히 중첩 배열이나 복잡한 데이터 구조를 다룰 때는 array_merge_recursive()나 사용자 정의 함수로 한 단계 더 나아가는 것을 권장한다.