php-standard-library/range
Range types for PHP integer sequences with built-in iteration support. Use range objects to represent start/end bounds and step through values predictably. Part of PHP Standard Library; see docs, contribute, or report issues on GitHub.
Installation:
composer require php-standard-library/range
Add to composer.json under require:
"php-standard-library/range": "^6.2"
First Use Case:
Replace a manual loop with a Range object:
use PHPStandardLibrary\Range\Range;
// Before: Manual loop
for ($i = 1; $i <= 10; $i++) {
echo $i;
}
// After: Range iteration
foreach (Range::from(1, 10) as $i) {
echo $i;
}
Key Classes:
Range: Core class for integer sequences.LazyRange: Memory-efficient iterator for large ranges (e.g., batch processing).RangeException: Handle invalid ranges (e.g., start > end).Where to Look First:
src/Range.php for core methods (e.g., from(), step(), lazy()).tests/ for usage examples and edge cases.// Inclusive range (1–10)
$range = Range::from(1, 10);
// Exclusive range (1–9)
$range = Range::from(1, 10, 1, false);
// Step ranges (e.g., even numbers)
$evens = Range::from(2, 20, 2);
Use lazy() to avoid memory issues (e.g., processing 1M+ records):
use PHPStandardLibrary\Range\LazyRange;
$lazyRange = Range::from(1, 1_000_000)->lazy();
foreach ($lazyRange as $id) {
// Process one record at a time (memory-efficient)
User::find($id)->update(['status' => 'processed']);
}
Combine with Laravel’s Collection for functional operations:
use Illuminate\Support\Collection;
$range = Range::from(1, 5);
$users = $range->map(fn($id) => User::find($id))->toCollection();
// Filter even IDs
$evens = $range->filter(fn($id) => $id % 2 === 0)->toArray();
Add a whereInRange method to Eloquent queries:
// In a Model or Query Builder extension
public function scopeWhereInRange($query, string $column, int $start, int $end, int $step = 1)
{
return $query->whereIn($column, Range::from($start, $end, $step)->toArray());
}
// Usage
User::whereInRange('id', 100, 200, 2)->get();
Dispatch lazy ranges to queue workers:
// Job class
public function handle()
{
$range = Range::from(1, 1_000_000)->lazy();
foreach ($range as $id) {
ProcessUserJob::dispatch($id);
}
}
Use ranges for type-safe validation (e.g., age constraints):
use PHPStandardLibrary\Range\Range;
function validateAge(int $age): void
{
$validAges = Range::from(18, 65);
if (!$validAges->contains($age)) {
throw new \InvalidArgumentException("Age must be between 18 and 65.");
}
}
Parse range strings from request parameters:
// Route: /users?ids=100-200:2
$rangeStr = request('ids'); // "100-200:2"
$range = Range::fromString($rangeStr); // Range(100, 200, 2)
$users = User::whereIn('id', $range->toArray())->get();
Register a Range facade for cleaner syntax:
// app/Providers/AppServiceProvider.php
use PHPStandardLibrary\Range\Range;
use Illuminate\Support\Facades\Facade;
class AppServiceProvider extends ServiceProvider
{
public function boot()
{
Facade::alias(Range::class, 'Range');
}
}
Extend Laravel Collections with range methods:
// app/Providers/AppServiceProvider.php
use Illuminate\Support\Collection;
Collection::macro('range', function ($start, $end, $step = 1) {
return $this->merge(Range::from($start, $end, $step)->toArray());
});
// Usage
$ids = collect([1, 2, 3])->range(4, 6); // [1, 2, 3, 4, 5, 6]
Generate test data using ranges:
// tests/Feature/UserTest.php
public function test_bulk_operations()
{
$range = Range::from(1, 100);
$users = $range->map(fn($id) => User::factory()->create(['id' => $id]));
$this->assertCount(100, $users);
}
Replace paginate() with custom range-based pagination:
// Controller
public function index(Request $request)
{
$page = $request->query('page', 1);
$perPage = $request->query('per_page', 20);
$start = ($page - 1) * $perPage + 1;
$end = $page * $perPage;
$range = Range::from($start, $end);
$users = User::whereIn('id', $range->toArray())->get();
return response()->json($users);
}
Range::from(1, 1) includes only 1 (inclusive by default). Use toArray() to verify:
$range = Range::from(1, 1);
var_dump($range->toArray()); // [1]
inclusive flag:
$range = Range::from(1, 1, 1, false); // Empty range
$lazy = Range::from(1, 1_000_000)->lazy();
foreach ($lazy as $item) {
// Process item
}
// OR
$lazy->close(); // Explicitly close if not fully consumed
Range::from(10, 1, -1) creates an infinite loop if not handled.assertValid():
$range = Range::from(10, 1, -1);
$range->assertValid(); // Throws RangeException if invalid
RangeException.intval() or a separate library for decimal ranges:
$range = Range::from(intval(1.5), intval(3.2)); // [2, 3]
Range objects may not serialize/deserialize cleanly (e.g., for caching).cache()->put('range', Range::from(1, 10)->toArray());
Range objects have a ~5% overhead vs. native loops for small ranges.// For tiny ranges (e.g., <100 items), native loops may be faster:
for ($i = 1; $i <= 10; $i++) { ... }
Add a debug method to your RangeHelper facade:
// app/Helpers/RangeHelper.php
public static function debug(Range $range)
{
\Log::debug('Range:', [
How can I help you explore Laravel packages today?