0

Array slicing and chunking: array_slice, array_chunk

Beginner5 min read·php-04-013

Concept

array_slice($array, $offset, $length, $preserve_keys) extracts a portion of an array without modifying the original. $offset is zero-indexed; negative values count from the end. $length is optional — omitting it takes everything from $offset to the end; negative length excludes that many elements from the end. $preserve_keys controls whether integer keys are reset (default false, resets to 0,1,2…) or kept from the original.

array_chunk($array, $size, $preserve_keys) splits an array into multiple arrays of at most $size elements each. Returns an array of arrays. The last chunk may have fewer than $size elements. $preserve_keys has the same behavior as in array_slice.

Common use cases: Pagination (array_slice($items, ($page-1)*$perPage, $perPage)), batching API calls into chunks of 100 (array_chunk($ids, 100)), extracting the first/last N items from a result set.

Performance note: Both functions create new arrays — they are O(n) in the size of the slice/chunks. For very large arrays being sliced repeatedly, consider using generators or SplFixedArray to work with offsets without full copies.

Code Example

php
<?php
declare(strict_types=1);

$fruits = ['apple', 'banana', 'cherry', 'date', 'elderberry', 'fig'];

// array_slice — basic slicing
$middle = array_slice($fruits, 2, 3);
// ['cherry', 'date', 'elderberry']

// Negative offset — from end
$last2 = array_slice($fruits, -2);
// ['elderberry', 'fig']

// Negative length — exclude last 2
$allButLast2 = array_slice($fruits, 0, -2);
// ['apple', 'banana', 'cherry', 'date']

// preserve_keys = true
$preserved = array_slice($fruits, 2, 2, preserve_keys: true);
// [2 => 'cherry', 3 => 'date'] — original indices preserved

// Pagination pattern
function paginate(array $items, int $page, int $perPage): array
{
    $offset = ($page - 1) * $perPage;
    return array_slice($items, $offset, $perPage);
}
$page1 = paginate($fruits, 1, 2); // ['apple', 'banana']
$page2 = paginate($fruits, 2, 2); // ['cherry', 'date']

// array_chunk — split into batches
$ids = range(1, 10); // [1,2,3,...,10]

$batches = array_chunk($ids, 3);
// [[1,2,3], [4,5,6], [7,8,9], [10]]  — last batch is smaller

foreach ($batches as $batch) {
    // Process each batch (e.g., bulk API call with 3 items at a time)
    echo "Processing: " . implode(', ', $batch) . "\n";
}

// Preserve keys in chunks
$assoc = ['a' => 1, 'b' => 2, 'c' => 3, 'd' => 4];
$chunks = array_chunk($assoc, 2, preserve_keys: true);
// [['a' => 1, 'b' => 2], ['c' => 3, 'd' => 4]]

// Without preserve_keys (default)
$chunks = array_chunk($assoc, 2);
// [[0 => 1, 1 => 2], [0 => 3, 1 => 4]] — keys reset per chunk

// Batch insert pattern
$rows = array_fill(0, 1000, ['name' => 'test', 'value' => 1]);
foreach (array_chunk($rows, 100) as $batch) {
    // db()->table('items')->insert($batch);
}

Interview Q&A

Q: How does array_slice handle negative offset and negative length?

Negative $offset counts from the end of the array — array_slice($arr, -3) returns the last 3 elements. Negative $length means "stop this many elements before the end" — array_slice($arr, 0, -2) returns all elements except the last 2. You can combine them: array_slice($arr, 2, -2) returns elements from index 2 up to (but not including) the last 2. This mirrors Python's list slicing syntax and is useful for "trim N from each end" operations.


Q: What is the difference between array_chunk with and without preserve_keys, and when does it matter?

Without preserve_keys (the default), each chunk has integer keys reset to 0, 1, 2, … — standard sequential arrays. This is what you want when iterating over chunks and the original index has no meaning. With preserve_keys: true, each chunk retains the original keys from the source array — essential when you have an associative array and need to match chunk elements back to their original keys, or when you're processing data where the original index carries semantic meaning (like a position-indexed dataset).