php-standard-library/io
Handle-based I/O abstractions for PHP: composable, testable streams and readers/writers designed to be async-ready. Part of PHP Standard Library, with docs and contribution links available via php-standard-library.dev.
Installation
composer require php-standard-library/io
For Laravel projects, consider adding it to require-dev if only used for testing or specific modules.
First Use Case: Async File Handling Replace Laravel’s synchronous file operations with async alternatives:
use PhpStandardLibrary\IO\FileHandle;
use PhpStandardLibrary\IO\FileReader;
$fileHandle = new FileHandle(storage_path('app/example.txt'));
$reader = new FileReader($fileHandle);
// Async read (requires async PHP environment like Swoole)
$content = yield $reader->readAsync();
Where to Look First
FileHandle, StreamHandle, and ResourceInterface for Laravel-specific use.*Async methods in the source (src/Async/).Replacing Laravel’s Storage Facade
Create a service provider to wrap Laravel’s Storage with IO abstractions:
// app/Providers/IOServiceProvider.php
use Illuminate\Support\ServiceProvider;
use PhpStandardLibrary\IO\FileHandle;
class IOServiceProvider extends ServiceProvider {
public function register() {
$this->app->singleton('io.storage', function () {
return new class {
public function read($path) {
$handle = new FileHandle(storage_path($path));
return (new FileReader($handle))->read();
}
};
});
}
}
Async Job Processing
Use IO for large file operations in queued jobs:
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use PhpStandardLibrary\IO\FileHandle;
class ProcessLargeFile implements ShouldQueue {
use Queueable;
public function handle() {
$handle = new FileHandle(storage_path('large_file.csv'));
$reader = new FileReader($handle);
// Process in chunks asynchronously
while (!$reader->eof()) {
$chunk = yield $reader->readLineAsync();
// Process chunk...
}
}
}
HTTP Client Integration
Extend Laravel’s Http facade with async IO requests:
use PhpStandardLibrary\IO\HttpClient;
$client = new HttpClient();
$response = yield $client->getAsync('https://api.example.com/data');
Testing with Mock Handles
Replace Laravel’s Storage::fake() with IO mocks:
use PhpStandardLibrary\IO\MockHandle;
$mockHandle = new MockHandle(['content' => 'test']);
$reader = new FileReader($mockHandle);
$this->assertEquals('test', $reader->read());
IO interfaces to Laravel’s container for dependency injection:
$this->app->bind(
PhpStandardLibrary\IO\ResourceInterface::class,
PhpStandardLibrary\IO\FileHandle::class
);
IO async operations:
public function handle($request, Closure $next) {
$response = $next($request);
if ($response->isAsync()) {
$response->then(fn() => log('Async IO completed'));
}
return $response;
}
IO events (e.g., file read/write) via Laravel’s event system:
use PhpStandardLibrary\IO\Events\FileRead;
event(new FileRead($handle, $content));
Async Environment Requirements
*Async) require an async PHP runtime (e.g., Swoole, RoadRunner).Swoole\Coroutine.Resource Leaks
Handle objects can lead to memory leaks.finally blocks or context managers:
$handle = new FileHandle('file.txt');
try {
$reader = new FileReader($handle);
$content = $reader->read();
} finally {
$handle->close();
}
Laravel Facade Conflicts
Storage or Http facades.IO classes or use aliases:
class_alias(
PhpStandardLibrary\IO\FileHandle::class,
'App\IO\FileHandle'
);
Testing Quirks
IO handles may not work with Laravel’s Storage mocks.IO mocks directly or create a hybrid test setup:
Storage::fake('local');
$mockHandle = new MockHandle(['content' => 'test']);
Async Deadlocks
yield keywords or improper coroutine context.Swoole\Coroutine::stats() to monitor active coroutines.Handle State Corruption
Handle objects behave unexpectedly after reuse.$clone = clone $handle; // Safe for async operations
Performance Bottlenecks
Xdebug or Blackfire to compare:
IO async methods vs. Laravel’s sync methods.yield vs. native PHP async.Custom Handles
Extend ResourceInterface for Laravel-specific resources (e.g., database streams):
class DatabaseHandle implements ResourceInterface {
public function read(): string {
return DB::table('logs')->first()->content;
}
}
Laravel Event Integration
Dispatch Laravel events from IO operations:
use Illuminate\Support\Facades\Event;
$reader = new FileReader($handle);
$content = $reader->read();
Event::dispatch(new FileReadEvent($handle, $content));
Async Queue Workers
Use IO in Laravel Horizon workers for async file processing:
class FileProcessor extends ShouldQueue {
public function handle() {
$handle = new FileHandle(storage_path('queue/file.txt'));
$content = yield $handle->readAsync();
// Process content...
}
}
Async Driver Configuration
php.ini has opcache.enable=0 for async PHP (e.g., Swoole).APP_ENV=async for async-specific behavior.Handle Timeout Settings
$handle = new FileHandle('file.txt', ['timeout' => 5.0]);
Laravel Cache Integration
IO handle states to avoid repeated disk/network calls:
$handle = new FileHandle('file.txt');
$cached = Cache::remember('file_content', 60, fn() => $handle->read());
Combine with Laravel Mixins
Use Laravel’s mixins to add IO methods to native classes:
Storage::mixin(new class {
public function ioRead($path) {
return (new FileReader(new FileHandle($this->path($path))))
->read();
}
});
Leverage Laravel’s Async Facades
Wrap IO async calls in Laravel’s async facades:
use Illuminate\Support\Facades\Async;
Async::onQueue('io')->call(function () {
$handle = new FileHandle('file.txt');
return $handle->readAsync();
});
Monitor Async Jobs
Use Laravel’s Horizon to track IO-powered async jobs:
// In a Horizon dashboard
Horizon::monitorJobs(function ($job) {
return $job->payload['command'] === 'process_with_io';
});
How can I help you explore Laravel packages today?