php-standard-library/range
Range types for integer sequences with iteration support, part of the PHP Standard Library. Provides typed, iterable integer ranges for clean sequence generation in PHP applications. Install via Composer and use alongside other php-standard-library packages.
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?