amphp/file
Non-blocking file I/O for PHP 8.1+ in the AMPHP ecosystem. Read/write files or stream via async file handles while keeping apps responsive. Uses multi-process by default, with optional eio/uv/parallel drivers when available.
Installation:
composer require amphp/file
Ensure PHP 8.1+ is used.
First Use Case: Read a file asynchronously:
use Amp\File;
$contents = File\read('path/to/file.txt');
echo $contents;
Check Available Drivers: Verify which filesystem driver is being used (blocking, parallel, ext-uv, ext-eio, etc.) via:
$driver = Amp\File\getFilesystemDriver();
echo get_class($driver);
Amp\File static methods (read, write, openFile, etc.) for high-level operations.Amp\File\openFile() for streaming or low-level file operations.Amp\File\getStatus() or helper methods like exists(), isFile(), etc.Read/Write Entire Files:
// Read
$contents = Amp\File\read('file.txt');
// Write (overwrites)
Amp\File\write('file.txt', 'New content');
// Append
Amp\File\append('file.txt', 'Appended content');
Streaming with File Handles:
$file = Amp\File\openFile('large_file.txt', 'r');
Amp\ByteStream\pipe($file, getStdout());
Check File Existence:
if (Amp\File\exists('file.txt')) {
echo "File exists!";
}
List Directory Contents:
$files = Amp\File\listFiles('directory/');
foreach ($files as $file) {
echo $file . "\n";
}
Create Directories Recursively:
Amp\File\createDirectoriesRecursively('path/to/new/dir');
Lock a File:
$file = Amp\File\openFile('file.txt', 'r+');
$file->lock(); // Exclusive lock
$file->write('Locked content');
$file->unlock();
Non-Blocking Lock Attempt:
if ($file->tryLock()) {
$file->write('Temporarily locked');
$file->unlock();
}
$mutex = new Amp\File\FileMutex('file.txt');
$mutex->acquire();
try {
// Critical section
Amp\File\write('file.txt', 'Safe update');
} finally {
$mutex->release();
}
$mutex = new Amp\File\KeyedFileMutex('locks_dir/');
$key = 'resource_123';
$mutex->acquire($key);
try {
// Work with resource
} finally {
$mutex->release($key);
}
Service Provider Setup:
Bind the filesystem driver in AppServiceProvider:
use Amp\File;
use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider
{
public function register()
{
$this->app->singleton('amp.filesystem', function () {
return File\getFilesystemDriver();
});
}
}
Custom File System (Laravel 5.5+):
Extend Laravel's Filesystem to use amphp/file:
use Amp\File;
use Illuminate\Contracts\Filesystem\Filesystem;
class AmpFilesystem implements Filesystem
{
public function read($path)
{
return File\read(storage_path($path));
}
// Implement other Filesystem methods...
}
use Amp\Loop;
$files = ['file1.txt', 'file2.txt', 'file3.txt'];
$promises = [];
foreach ($files as $file) {
$promises[] = Amp\File\read($file);
}
$contents = await Amp\Promise\all($promises);
amphp/react):
use Amp\File;
use Amp\React\EventLoop;
$loop = EventLoop::get();
$file = Amp\File\openFile('watch_me.txt', 'r');
$loop->onReadable($file, function () use ($file) {
$data = $file->read();
echo "File changed: " . $data;
});
$driver = Amp\File\getFilesystemDriver();
if ($driver instanceof Amp\File\BlockingFilesystemDriver) {
// Fallback logic for blocking operations
}
Blocking Driver Performance:
BlockingFilesystemDriver uses PHP's blocking functions and will block the event loop. Prefer ParallelFilesystemDriver or extensions like ext-uv/ext-eio for production.File Handle Leaks:
$file = Amp\File\openFile('file.txt', 'r');
try {
// Use file
} finally {
$file->close();
}
onClose() for cleanup:
$file->onClose(function () {
echo "File closed!";
});
Path Normalization:
realpath() or Amp\File\resolveSymlink() to resolve symlinks before operations to avoid unexpected behavior.Concurrent File Operations:
File::lock() or FileMutex), concurrent reads/writes can corrupt data. Always use locks for critical sections.Driver-Specific Quirks:
ext-uv/ext-eio: May behave differently with append modes ('a'). Test thoroughly.LimitedWorkerPool for resource limits:
use Amp\File\ParallelFilesystemDriver;
use Amp\Worker\LimitedWorkerPool;
$pool = new LimitedWorkerPool(4); // Limit to 4 workers
$driver = new ParallelFilesystemDriver($pool);
Cancellation:
Cancellation object to File::read() to support cancellation:
$cancellation = Amp\Cancellation::create();
$contents = Amp\File\read('file.txt', $cancellation);
Seek Operations:
seek(), always check eof() or tell() to avoid unexpected behavior:
$file->seek(10, Amp\File\Whence::SEEK_SET);
if (!$file->eof()) {
$data = $file->read();
}
Check Driver in Use:
echo get_class(Amp\File\getFilesystemDriver());
Amp\File\ParallelFilesystemDriver, Amp\File\UvFilesystemDriver, etc.Log File Operations:
try-catch to log errors:
try {
$contents = Amp\File\read('file.txt');
} catch (\Throwable $e) {
\Log::error("File read failed: " . $e->getMessage());
}
Verify File Permissions:
Amp\File\isReadable()/Amp\File\isWritable() to debug permission issues:
if (!Amp\File\isReadable('file.txt')) {
throw new \RuntimeException("File not readable!");
}
Test Locking:
$file = Amp\File\openFile('file.txt', 'r+');
$file->lock();
// Simulate delay
Amp\delay(1000);
$file->unlock();
Amp\File\FilesystemDriver for custom storage (e.g., S3, database):
How can I help you explore Laravel packages today?