Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Process Laravel Package

amphp/process

Asynchronous process dispatcher for PHP (AMPHP) built for fibers and concurrency. Start and manage child processes cross-platform, stream stdout/stderr without blocking, set working directory and environment variables, powered by the Revolt event loop and Windows wrapper.

View on GitHub
Deep Wiki
Context7

Getting Started

Start by installing via Composer:

composer require amphp/process

Ensure your project uses an AMP-based async framework (e.g., amphp/amp, Danack/Anvil, or AsyncPHP/HttpServer) since this package relies on the AMP event loop. The most basic usage spawns a process, waits for output, and exits:

use Amp\Process\Process;
use Amp\Promise;

require 'vendor/autoload.php';

async function main(): Promise {
    $process = new Process(['php', '-r', 'echo "Hello from async!\n";']);
    $process->start();

    $output = '';
    foreach ($process->getStdout() as $chunk) {
        $output .= $chunk;
    }

    $exitCode = await $process->join();
    echo "Exit code: $exitCode\nOutput: $output\n";
}

Amp\Loop::run(fn() => main());

Look first at the Process class documentation and the examples/ directory in the repo for quick, runnable demos.


Implementation Patterns

  • Streaming long-running output: Use generators over stdout()/stderr() to consume data incrementally (e.g., tail logs or stream build output):
    foreach ($process->getStderr() as $chunk) {
        error_log("STDERR: $chunk");
    }
    
  • Interactive processes: Pipe input via write() and handle responses:
    $process = new Process(['cat']);
    $process->start();
    $process->write("hello\n");
    $process->write("world\n");
    $process->closeStdin(); // Signal EOF
    
  • Cancellation & timeouts: Use Amp\Promise + Amp\Timeout to kill hung processes:
    $timedOut = false;
    $process = new Process(['sleep', '10']);
    $process->start();
    
    try {
        await $process->join(1000); // 1s timeout
    } catch (Amp\TimeoutException $e) {
        $timedOut = true;
        $process->terminate();
    }
    
  • Process pools: Launch multiple processes concurrently for parallel execution (e.g., batch file conversion):
    $promises = [];
    foreach ($files as $file) {
        $process = new Process(['convert', $file, 'thumb_' . $file]);
        $process->start();
        $promises[] = $process->join();
    }
    await Amp\Promise\all($promises);
    
  • Signal handling: Listen for SIGINT/SIGTERM in CLI tools to gracefully kill child processes. Use the new getSignalName() helper to log human-readable signal names:
    $process->onExit(fn(int $signal) => {
        $signalName = \Amp\Process\getSignalName($signal);
        Logger::info("Process terminated by signal {$signalName ?? $signal}");
    });
    
  • Debugging signal exits: Leverage getSignalName() to log meaningful signal names when handling process termination:
    $signal = $process->getExitSignal();
    $signalName = \Amp\Process\getSignalName($signal);
    echo "Process exited with signal: {$signalName ?? 'unknown'}";
    

Gotchas and Tips

  • Standard streams must be consumed: If you don’t read from stdout/stderr, the process can deadlock due to full buffers (especially with interactive tools like ssh or python -i). Always yield or foreach the streams—even if you ignore the content.
  • Working directory is relative to the PHP process, not the script directory. Use chdir() or pass absolute paths in $process->start([...], ['cwd' => '/path/to/dir']).
  • write() returns a Promise<void> — you must await it if you rely on buffering guarantees. Failure to do so may drop input silently during high throughput.
  • join() blocks until exit, but you can pass a timeout in milliseconds (e.g., await $process->join(5000)) to prevent indefinite hangs.
  • Windows limitations: Signal handling (terminate(), kill()) relies on POSIX signals — limited support on Windows. Prefer terminate() over kill() for cross-platform safety. Note that getSignalName() requires ext-pcntl and will return null on Windows or without the extension.
  • Never mix with proc_open(): Running synchronous calls in the same loop breaks async semantics. Use amphp/process exclusively for all process management when in an AMP context.
  • Extension quirk: The library requires ext-uv or ext-event or the native stream_select fallback — ensure your environment supports async I/O. Check with php -m | grep -E 'uv|event'.
  • getSignalName() requires ext-pcntl: This helper function will return null if the signal number is not defined in the system or if ext-pcntl is unavailable. Handle this gracefully in production code:
    $signalName = \Amp\Process\getSignalName($signal);
    if ($signalName === null) {
        // Fallback to raw signal number or custom logic
    }
    
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
jayeshmepani/jpl-moshier-ephemeris-php
elnasnato/laraliveui
labrodev/rest-sdk
sampaui/sampaui
babelqueue/php-sdk
facebook/capi-param-builder-php
babelqueue/symfony
hamzi/corewatch
minionfactory/raw-hydrator
hexters/coinpayment
rjcodes/rjcms
act-training/laravel-permissions-manager
alimarchal/laravel-chart-of-accounts
babenkoivan/elastic-scout-driver
mkwebdesign/filament-watchdog-v5
renatomarinho/laravel-page-speed
zedmagdy/filament-business-hours
renatovdemoura/blade-elements-ui
devgeek/beacon-admin
benjamin-rqt/data-watcher-bundle