php-standard-library/process
Typed, non-blocking PHP API for spawning, monitoring, and controlling child processes. Manage stdin/stdout/stderr streams, retrieve exit codes, and handle timeouts and signals with a clean, reliable interface for long-running and parallel tasks.
Installation
composer require php-standard-library/process
No additional configuration is required—just autoload.
First Use Case: Running a Simple Command
use PhpStandardLibrary\Process\Process;
$process = new Process('ls -la');
$process->run();
if ($process->isSuccessful()) {
echo "Output:\n" . $process->getOutput();
} else {
echo "Error: " . $process->getErrorOutput();
}
Key Entry Points
Process::run() – Execute the command.Process::isSuccessful() – Check exit code (0 = success).Process::getOutput() / Process::getErrorOutput() – Retrieve streams.Process::setWorkingDirectory() – Change cwd for the subprocess.Process::setEnv() – Override environment variables.$process = new Process(['git', 'pull', 'origin', 'main']);
$process->setWorkingDirectory(base_path());
$process->run();
if (!$process->isSuccessful()) {
throw new RuntimeException("Git pull failed: " . $process->getErrorOutput());
}
$process = new Process('tail -f /var/log/app.log');
$process->start(); // Non-blocking start
while ($process->isRunning()) {
echo $process->getOutput(); // Stream output incrementally
usleep(100000); // Throttle
}
$process = new Process('php artisan migrate');
$process->setEnv(['APP_ENV' => 'testing']);
$process->run();
use Symfony\Component\Process\Process as SymfonyProcess; // Alias if needed
$process = new Process('php artisan queue:work --once');
$process->run();
Error Handling
Always check $process->isSuccessful() and log $process->getErrorOutput() for debugging.
Timeouts
Use Process::setTimeout() to avoid hanging:
$process->setTimeout(30); // 30 seconds
Dependency Injection
Bind the Process class in Laravel’s service container for reusable instances:
$this->app->bind(Process::class, function () {
return new Process(config('app.command'));
});
Laravel Artisan Integration Wrap in a custom command for reusability:
use PhpStandardLibrary\Process\Process;
class RunProcessCommand extends Command {
protected $signature = 'app:run {command}';
public function handle() {
$process = new Process($this->argument('command'));
$process->run();
$this->line($process->getOutput());
}
}
Blocking Calls
run() blocks until completion. Use start() + isRunning() for async workflows.$process->isRunning() in a loop or use Process::wait() for non-blocking checks.Output Buffering
ffmpeg) buffer output. Use --no-buffer flags or stream incrementally.Environment Variable Leaks
setEnv() overrides but doesn’t merge. Explicitly pass all required vars:
$process->setEnv([
'DB_HOST' => env('DB_HOST'),
'APP_DEBUG' => 'false',
]);
Working Directory Permissions
chmod or umask(0) if needed:
$process->setWorkingDirectory(storage_path('logs'));
Signal Handling
SIGKILL/SIGTERM. Use Process::terminate() for graceful stops.Log Raw Output
file_put_contents(
storage_path('logs/process_debug.log'),
$process->getOutput() . "\n" . $process->getErrorOutput()
);
Check Exit Codes
$process->getExitCode() for granular checks:
if ($process->getExitCode() === 127) {
// Command not found
}
Dry Runs Simulate commands without execution:
$process = new Process('ls /nonexistent');
$process->dryRun(); // Returns false, no subprocess spawned
Custom Process Builders Create a decorator for reusable configurations:
class GitProcess extends Process {
public function __construct(string $repoPath) {
parent::__construct(['git', '--git-dir=' . $repoPath]);
}
}
Event Listeners
Hook into Process::start()/Process::run() to log or modify behavior:
$process->onStart(function () {
Log::info('Process started: ' . $this->getCommandLine());
});
Laravel Service Provider Register a global helper:
if (!function_exists('run_process')) {
function run_process(string $command) {
$process = new Process($command);
$process->run();
return $process;
}
}
How can I help you explore Laravel packages today?