# RFC: Array Search Range

- Status: Draft
- Authors: Sepehr Mahmoudi
- Date: 2026-08-11
- Version: 0.1 (Under Discussion)
- Original: https://wiki.php.net/rfc/array_search_range
- Page: https://externals.io/rfc/array_search_range
- More for agents: search with https://externals.io/search.md?q={query} · RFCs at https://externals.io/rfc.md · JSON API at https://externals.io/api · documentation at https://externals.io/llms.txt

## Discussions on the mailing list

- [\[RFC\] array_search_range](https://externals.io/message/132204.md) — started on 2026-08-12, 11 messages
- [\[RFC\] array_search_range() function](https://externals.io/message/132231.md) — started on 2026-08-17, 14 messages

---

## Introduction

This RFC proposes a new core function named `array_search_range()`.

The function searches for a value within a positional range of an existing array. It is intended for cases where an application needs to search only a part of an array, without first creating an intermediate array using `array_slice()`.

## Proposed Function Signature

```php
function array_search_range(
    mixed $needle,
    array $haystack,
    int $offset = 0,
    ?int $length = null,
    bool $strict = false,
): int | string | false {}
```

## Summary

`array_search_range()` searches for the first matching value in a selected range of an array and returns the original key of that value.

Like `array_search()`, it returns the actual key of the element. If no value matches, it returns `false`.

## Motivation

Currently, searching a portion of an array requires `array_slice()`:

```php
$haystack = ['PHP', 'Python', 'Ruby', 'PHP'];
$range = array_slice($haystack, 1, 3);
$key = array_search('PHP', $range, true);
```

This approach has two main drawbacks:

```
1. It creates an intermediate array, which consumes additional memory.
2. It requires two function calls instead of one.
```

The proposed function iterates over the original array directly, avoiding unnecessary memory allocation for an intermediate structure.

## Use Cases

#### Pagination on Large Arrays

When you have an array with a hundred thousand elements and you only want to process a specific range, you currently have to copy the whole slice with `array_slice()` or loop over everything. `array_search_range()` returns only the indices of that range, with no intermediate copy.

```php
$records = $db->fetchAll(); // 100,000 rows
$pageSize = 20;
$page = 3;
 
$start = ($page - 1) * $pageSize;
$id = array_search_range($targetId, $records, $start, $pageSize, true);
```

#### Processing Large Log Files

You read a big log file into an array and you want to find only the lines within a specific time range. Instead of a full scan or a copy, you get just the relevant positions.

```php
$lines = file('access.log'); // 500,000 lines
$needle = 'ERROR';
 
// Find the first error within lines 100,000 to 200,000
$lineNumber = array_search_range($needle, $lines, 100000, 100000);
```

#### Queues

When you want to find items between two positions without modifying or copying the queue. The function returns only the indices, leaving the queue untouched.

```php
$queue = ['job_1', 'job_2', 'job_3', 'job_4'];
 
// Find 'job_3' within positions 1 to 3, queue remains intact
$position = array_search_range('job_3', $queue, 1, 3);
```

#### Database Cache

When you cache a query result in an array and you want to find a specific range of results without re-running the query. Instead of copying records, you just get the indices.

```php
$cache = ['u_100', 'u_101', 'u_102', 'u_103', 'u_104'];
 
$user = array_search_range('u_103', $cache, 2, 3, true);
// string(5) "u_103"
```

#### Why This Function Is Worth It

- **Memory:** no copy means memory usage stays constant
- **Speed:** a bounded search instead of a full scan
- **Simplicity:** a small function, with no dependency on a large lazy slice project
- **Available now:** usable today, not after a multi-month RFC

## Parameters

#### $needle

The value to search for.

#### $haystack

The array in which the search is performed.

#### $offset

The zero-based positional offset at which searching begins.

- If `$offset` is negative, searching begins relative to the end of the array.
- If `$offset` is out of bounds (greater than array size), the function returns `false`.

#### $length

The number of elements to inspect.

- When `null`, the function searches from `$offset` to the end of the array.
- If the requested length exceeds the remaining elements, the function searches until the end.
- If `$length` is 0, the function returns `false`.
- If `$length` is negative, the search excludes that number of elements from the end.

#### $strict

Whether to use strict comparison (`===` vs `==`).

## Detailed Behavior

#### Positional Range Versus Array Keys

The range is defined by positional order, not by the values of keys.

```php
$haystack = [100 => 'a', 500 => 'b', 700 => 'c'];
 
// Search starts at the 2nd element (position 1), even if its key is 500
$key = array_search_range('b', $haystack, 1, 1);
 
var_dump($key); // int(500)
```

#### Mixed Keys Example

The function correctly preserves and returns the original keys regardless of whether they are integers or strings.

```php
$haystack = ['a' => 'foo', 'b' => 'bar', 5 => 'baz'];
 
$key = array_search_range('baz', $haystack, 2, 1, true);
 
var_dump($key); // int(5)
```

#### Error Handling

- If `$offset` is invalid or outside the array bounds, the function returns `false`.
- This function does not throw exceptions for valid input ranges, maintaining

consistency with `array_slice()`.

## Examples

#### Basic Search

```php
$haystack = ['PHP', 'Python', 'Ruby', 'PHP'];
 
$key = array_search_range('Ruby', $haystack);
 
var_dump($key); // int(2)
```

#### Search Within a Specific Range

```php
$haystack = ['PHP', 'Python', 'Ruby', 'PHP'];
 
$key = array_search_range('PHP', $haystack, 1, 3, true);
 
var_dump($key); // int(3)
```

#### Persian Associative Array Example

```php
$haystack = ['u_100' => 'سپهر', 'u_101' => 'علی', 'u_102' => 'رضا', 'u_103' => 'مریم'];
 
$key = array_search_range('مریم', $haystack, 2, 2, true);
 
var_dump($key); // string(5) "u_103"
```

## Performance Considerations

Compared to `array_slice()`, this function avoids creating a temporary `HashTable`. For an array of 100,000 elements, searching a range avoids allocating memory for the temporary slice, reducing GC pressure and CPU cycles required for array duplication.

```
Memory usage: constant (no intermediate array)
Time complexity: O(n) in the worst case, bounded by the requested range
GC pressure: reduced (no temporary HashTable allocated)
```

## Implementation Plan

The implementation focuses on direct `HashTable` iteration. The code will be submitted as a Pull Request to php-src.

Full PHPT test coverage for edge cases including negative offsets, negative lengths, and mixed key types is included.

## Proposed PHP Version

PHP 8.6.

## Changelog

- 0.1 — Initial draft by Sepehr Mahmoudi.

## Polyfill

```php
if (!function_exists('array_search_range')) {
    function array_search_range(
        mixed $needle,
        array $haystack,
        int $offset = 0,
        ?int $length = null,
        bool $strict = false
    ): int|string|false {
        $count = count($haystack);
 
        if ($offset < 0) {
            $offset = max(0, $count + $offset);
        }
 
        if ($length === null) {
            $length = $count - $offset;
        } elseif ($length < 0) {
            $length = $count - $offset + $length;
        }
 
        if ($length <= 0 || $offset >= $count) {
            return false;
        }
 
        $slice = array_slice($haystack, $offset, $length, true);
        return array_search($needle, $slice, $strict);
    }
}
```
