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
Add to composer.json under require-dev if using only for testing:
"require-dev": {
"php-standard-library/io": "^1.0"
}
First Use Case: File Reading
use PhpStandardLibrary\IO\FileHandle;
use PhpStandardLibrary\IO\FileReader;
$handle = new FileHandle('/path/to/file.txt');
$reader = new FileReader($handle);
$content = $reader->read();
Where to Look First
README.md for basic examples.src/ for core classes (FileHandle, StreamHandle, Reader, Writer).tests/ directory for usage patterns and edge cases.Composable I/O Operations Chain readers/writers for complex pipelines:
$handle = new FileHandle('input.txt');
$reader = new FileReader($handle);
$writer = new FileWriter(new MemoryHandle());
$writer->write($reader->read());
Async-Ready Design
Use AsyncFileReader for non-blocking operations:
$asyncReader = new AsyncFileReader($handle);
$content = yield $asyncReader->read(); // In a coroutine
Testing Abstractions
Mock Handle interfaces for unit tests:
$mockHandle = $this->createMock(HandleInterface::class);
$mockHandle->method('read')->willReturn('test data');
$reader = new FileReader($mockHandle);
$this->assertEquals('test data', $reader->read());
Storage facade in a custom Handle:
class LaravelFileHandle implements HandleInterface {
public function __construct(private Filesystem $filesystem, private string $path) {}
public function read(): string {
return $this->filesystem->get($this->path);
}
}
EventHandle for pub/sub I/O (e.g., Kafka, Redis Streams).Console for interactive I/O:
$handle = new ConsoleInputHandle();
$reader = new FileReader($handle); // Reuse logic for CLI/stdin
Resource Leaks
Always close handles explicitly or use __destruct():
$handle = new FileHandle('file.txt');
try {
$reader = new FileReader($handle);
// ...
} finally {
$handle->close();
}
Tip: Implement HandleInterface::close() in custom handles.
Async Caveats
yield support).Line Endings
FileReader preserves OS line endings (\n, \r\n). Use trim() or str_replace() for normalization.
try-catch:
try {
$reader->read();
} catch (IOException $e) {
Log::error("I/O failed: {$e->getMessage()}");
}
HandleInterface to log operations:
class LoggingHandle implements HandleInterface {
public function read(): string {
Log::debug("Reading from handle");
return $this->delegate->read();
}
}
Custom Protocols
Implement HandleInterface for HTTP, databases, or queues:
class HttpHandle implements HandleInterface {
public function read(): string {
return file_get_contents($this->url);
}
}
Compression Decorate handles for gzip/brotli:
class GzipHandle implements HandleInterface {
public function __construct(private HandleInterface $handle) {}
public function read(): string {
return gzdecode($this->handle->read());
}
}
Laravel Service Providers Bind interfaces to implementations:
$this->app->bind(HandleInterface::class, function ($app) {
return new FileHandle(config('app.storage_path').'/file.txt');
});
How can I help you explore Laravel packages today?