배열에서 특정 범위의 요소만 필요한데, 반복문을 돌면서 조건을 맞춰서 새로운 배열을 만들고 있진 않을까? 대부분의 개발자들은 array_slice() 함수의 정확한 동작 방식을 모른 채 인터넷에서 가져온 코드를 그냥 복사해 붙인다. 특히 음수 인자나 preserve_keys 옵션 같은 세부 옵션은 제대로 이해 못 하고 넘어가는 경우가 많다. 이번에는 array_slice()가 정확히 뭔지, 언제 어떻게 쓰는지, 그리고 실전에서 자주 하는 실수가 뭔지 완벽하게 정리해서 소개하겠다.
array_slice()는 배열의 일부를 잘라내서 새로운 배열로 반환하는 함수다. 원본 배열은 건드리지 않고, 지정한 오프셋(시작점)부터 길이(length)만큼의 요소만 추출한다.
기본 문법:
array_slice(array &$array, int $offset, ?int $length = null, bool $preserve_keys = false): array
각 파라미터 설명:
$array: 대상 배열$offset: 시작 위치 (양수면 앞에서부터, 음수면 뒤에서부터)$length: 추출할 요소 개수 (생략하면 끝까지, 음수면 뒤에서부터 제외)$preserve_keys: 원본 배열의 키를 유지할지 여부 (기본값: false, 키 재인덱싱)
배열의 앞에서부터 지정한 위치부터 시작해서 요소를 추출한다.
// ✗ 잘못된 방법: 반복문으로 수동 구현
$arr = ['a', 'b', 'c', 'd', 'e'];
$result = [];
for ($i = 1; $i < 4; $i++) {
$result[] = $arr[$i];
}
// $result = ['b', 'c', 'd']
// 코드가 길고, 실수하기 쉬움
// ✓ 올바른 방법: array_slice 사용
$arr = ['a', 'b', 'c', 'd', 'e'];
$result = array_slice($arr, 1, 3);
// $result = ['b', 'c', 'd']
// 오프셋 1부터 3개의 요소 추출
배열의 끝에서부터 역순으로 위치를 지정할 수 있다. -1은 마지막 요소, -2는 마지막에서 두 번째다.
$arr = ['a', 'b', 'c', 'd', 'e'];
// 마지막 2개 요소만 가져오기
$result = array_slice($arr, -2);
// $result = ['d', 'e']
// 마지막 3개 중에서 처음 2개만 가져오기
$result = array_slice($arr, -3, 2);
// $result = ['c', 'd']
// -3은 인덱스 2(c)를 의미하고, 그 위치부터 2개 추출
length를 음수로 지정하면 끝에서부터 그만큼 제외한다.
$arr = ['a', 'b', 'c', 'd', 'e'];
// 첫 번째부터 마지막 2개를 제외한 모든 요소
$result = array_slice($arr, 0, -2);
// $result = ['a', 'b', 'c']
// 끝에서 2개(d, e)를 제외
// 인덱스 1부터 끝에서 1개를 제외
$result = array_slice($arr, 1, -1);
// $result = ['b', 'c', 'd']
// 인덱스 1부터 시작해서 끝에서 e를 제외
연관 배열(키-값 쌍)일 때 원본 배열의 키를 그대로 유지하려면 preserve_keys를 true로 설정한다. 기본값은 false로, 키를 재인덱싱한다.
$arr = ['id' => 1, 'name' => 'Alice', 'email' => 'alice@test.com', 'age' => 25];
// ✗ 잘못된 방법: 기본값 그대로 사용
$result = array_slice($arr, 1, 2);
var_dump($result);
// array(2) { [0]=> string(5) "Alice" [1]=> string(16) "alice@test.com" }
// 원본의 'name', 'email' 키가 사라지고 0, 1로 재인덱싱됨
// ✓ 올바른 방법: preserve_keys를 true로 설정
$result = array_slice($arr, 1, 2, true);
var_dump($result);
// array(2) { ["name"]=> string(5) "Alice" ["email"]=> string(16) "alice@test.com" }
// 원본의 'name', 'email' 키가 유지됨
게시판에서 한 페이지에 10개의 글을 표시하는 페이징을 구현해보자. 이것은 array_slice()의 가장 실용적인 사용 사례다.
<?php
// 전체 게시글 목록 (실제로는 DB에서 쿼리)
$posts = [
['id' => 1, 'title' => '첫 번째 글', 'views' => 150],
['id' => 2, 'title' => '두 번째 글', 'views' => 200],
['id' => 3, 'title' => '세 번째 글', 'views' => 120],
['id' => 4, 'title' => '네 번째 글', 'views' => 350],
['id' => 5, 'title' => '다섯 번째 글', 'views' => 280],
['id' => 6, 'title' => '여섯 번째 글', 'views' => 90],
['id' => 7, 'title' => '일곱 번째 글', 'views' => 450],
['id' => 8, 'title' => '여덟 번째 글', 'views' => 310],
['id' => 9, 'title' => '아홉 번째 글', 'views' => 180],
['id' => 10, 'title' => '열 번째 글', 'views' => 220],
['id' => 11, 'title' => '열한 번째 글', 'views' => 165],
['id' => 12, 'title' => '열두 번째 글', 'views' => 340],
];
// 페이징 설정
$per_page = 3; // 한 페이지에 3개씩 표시 (실제로는 10개)
$current_page = isset($_GET['page']) ? (int)$_GET['page'] : 1;
// offset 계산
$offset = ($current_page - 1) * $per_page;
// 현재 페이지의 글들만 추출
$page_posts = array_slice($posts, $offset, $per_page);
// 전체 페이지 수
$total_pages = ceil(count($posts) / $per_page);
echo "<h2>현재 페이지: {$current_page} / {$total_pages}</h2>";
echo "<ul>";
foreach ($page_posts as $post) {
echo "<li>[ID: {$post['id']}] {$post['title']} (조회수: {$post['views']})</li>";
}
echo "</ul>";
// 페이지네이션 링크
echo "<div>";
for ($i = 1; $i <= $total_pages; $i++) {
if ($i === $current_page) {
echo "<strong>[{$i}]</strong> ";
} else {
echo "<a href='?page={$i}'>[{$i}]</a> ";
}
}
echo "</div>";
?>
출력 결과 (page=2일 때):
현재 페이지: 2 / 4
- [ID: 4] 네 번째 글 (조회수: 350)
- [ID: 5] 다섯 번째 글 (조회수: 280)
- [ID: 6] 여섯 번째 글 (조회수: 90)
[1] [2] [3] [4]
// ✗ 잘못된 코드
$user_data = ['user_id' => 42, 'username' => 'john', 'email' => 'john@test.com'];
$sliced = array_slice($user_data, 1, 2);
var_dump($sliced);
// array(2) { [0]=> string(4) "john" [1]=> string(14) "john@test.com" }
// 키 정보가 모두 손실됨 - API 응답이나 DB 결과에서 키는 중요함!
// ✓ 올바른 코드
$sliced = array_slice($user_data, 1, 2, true);
var_dump($sliced);
// array(2) { ["username"]=> string(4) "john" ["email"]=> string(14) "john@test.com" }
// 키가 유지되어 데이터의 의미가 명확함
$arr = ['a', 'b', 'c'];
// array_slice는 범위를 초과해도 가능한 범위까지만 반환함
$result = array_slice($arr, 1, 100);
var_dump($result);
// array(2) { [0]=> string(1) "b" [1]=> string(1) "c" }
// 100개를 요청했지만 남은 2개만 반환 - 에러 없음
// 음수 오프셋으로 배열 크기를 벗어나도 안전함
$result = array_slice($arr, -100, 2);
var_dump($result);
// array(2) { [0]=> string(1) "a" [1]=> string(1) "b" }
// -100은 배열의 시작보다 훨씬 앞이므로, 배열 시작부터 반환됨
array_slice()는 읽기 전용이고, array_splice()는 원본을 수정
$arr = ['a', 'b', 'c', 'd', 'e'];
// ✗ array_slice - 원본 배열이 변하지 않음
$result = array_slice($arr, 1, 2);
echo "Result: " . implode(',', $result) . "\n"; // b,c
echo "Original: " . implode(',', $arr) . "\n"; // a,b,c,d,e (그대로!)
// ✓ array_splice - 원본 배열이 변함
$arr2 = ['a', 'b', 'c', 'd', 'e'];
$result2 = array_splice($arr2, 1, 2);
echo "Result: " . implode(',', $result2) . "\n"; // b,c
echo "Original: " . implode(',', $arr2) . "\n"; // a,d,e (변함!)
$arr = ['a', 'b', 'c', 'd', 'e'];
// 여기서 -2는 '인덱스 3(d)'을 의미
$result = array_slice($arr, -2, 1);
var_dump($result);
// array(1) { [0]=> string(1) "d" }
// -2 위치(d)부터 1개만 가져옴
// 음수 offset은 "끝에서부터 몇 번째"라는 뜻이지,
// "끝에서부터 음수만큼" 이라는 뜻이 아님!
echo "위치 계산: 배열 길이 5 + offset(-2) = 인덱스 3\n";
array_slice()는 배열을 일부만 추출해야 할 때의 정석이다. 페이징, 최신 N개 항목 필터링, 배열 분할 등 웹 개발에서 매일 마주치는 상황들을 깔끔하게 처리할 수 있다. 특히 음수 인자와 preserve_keys 옵션을 제대로 이해하면, 복잡한 반복문을 한 줄로 줄일 수 있다. 이 글의 "실전 예제" 섹션을 참고해 실제 프로젝트에서 페이징 기능을 구현해보면, array_slice()의 강력함을 느낄 수 있을 것이다. 작은 함수 하나를 제대로 알고 쓰는 것이 모여서 코드 품질을 높이고 버그를 줄인다.