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

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.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Steps

  1. Installation

    composer require php-standard-library/process
    

    No additional configuration is required—autoloads via Composer.

  2. First Use Case: Running a Command in a Laravel Artisan Command

    use PhpStandardLibrary\Process\Process;
    
    class ExampleCommand extends Command
    {
        protected $signature = 'example:run-command';
        public function handle()
        {
            $process = new Process(['ls', '-la']);
            $process->run();
    
            if ($process->isSuccessful()) {
                $this->info($process->getOutput());
            } else {
                $this->error($process->getErrorOutput());
            }
        }
    }
    

    Run with:

    php artisan example:run-command
    
  3. Key Methods to Explore First

    • Process::run() – Execute the command synchronously.
    • Process::start() – Start asynchronously (non-blocking).
    • Process::isSuccessful() – Check exit code (returns true if exit code is 0).
    • Process::getOutput() / Process::getErrorOutput() – Retrieve streams.
    • Process::setTimeout() – Set a timeout in seconds (default: null = no timeout).

Implementation Patterns

Workflows in Laravel

1. Running External Commands in Artisan Commands

use PhpStandardLibrary\Process\Process;

class DeployCommand extends Command
{
    protected $signature = 'deploy:run-migrations';
    public function handle()
    {
        $process = new Process(['php', 'artisan', 'migrate', '--force']);
        $process->setWorkingDirectory(base_path());
        $process->run();

        if (!$process->isSuccessful()) {
            throw new RuntimeException(
                "Migrations failed: " . $process->getErrorOutput()
            );
        }
    }
}

2. Non-Blocking Process Execution (e.g., Long-Running Tasks)

use PhpStandardLibrary\Process\Process;

class ProcessJob implements ShouldQueue
{
    public function handle()
    {
        $process = new Process(['docker', 'build', '-t', 'app', '.']);
        $process->start(); // Non-blocking

        while ($process->isRunning()) {
            $output = $process->getOutput();
            if (!empty($output)) {
                Log::info($output); // Stream output in real-time
            }
            usleep(100000); // Throttle
        }

        if (!$process->isSuccessful()) {
            Log::error($process->getErrorOutput());
            throw new ProcessFailedException($process->getErrorOutput());
        }
    }
}

3. Environment-Specific Process Execution

use PhpStandardLibrary\Process\Process;

class TestCommand extends Command
{
    protected $signature = 'test:run';
    public function handle()
    {
        $process = new Process(['phpunit']);
        $process->setEnv([
            'APP_ENV' => 'testing',
            'DB_CONNECTION' => 'sqlite',
        ]);
        $process->run();

        $this->line($process->getOutput());
    }
}

4. Integration with Laravel Queues for Async Tasks

use PhpStandardLibrary\Process\Process;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;

class ProcessImageJob implements ShouldQueue
{
    use Queueable;

    public function handle()
    {
        $process = new Process(['ffmpeg', '-i', 'input.mp4', 'output.mp4']);
        $process->setTimeout(300); // 5 minutes
        $process->run();

        if (!$process->isSuccessful()) {
            throw new RuntimeException(
                "FFmpeg failed: " . $process->getErrorOutput()
            );
        }
    }
}

Integration Tips

  1. Leverage Laravel’s Service Container Bind the Process class for dependency injection:

    $this->app->bind(Process::class, function () {
        return new Process(config('app.default_command'));
    });
    

    Then inject it into controllers/commands:

    public function __construct(private Process $process) {}
    
  2. Use Facades for Convenience (Optional) Create a facade to simplify usage:

    // app/Providers/AppServiceProvider.php
    use Illuminate\Support\Facades\Facade;
    use PhpStandardLibrary\Process\Process;
    
    class AppServiceProvider extends ServiceProvider
    {
        public function boot()
        {
            Facade::register('Process', function () {
                return new Process(config('app.default_command'));
            });
        }
    }
    

    Now use Process::run() directly in views/controllers.

  3. Handle Timeouts Gracefully Always set a timeout to avoid hanging:

    $process->setTimeout(60); // 60 seconds
    $process->run();
    
    if ($process->isTimedOut()) {
        Log::warning('Process timed out');
    }
    
  4. Log Process Output for Debugging Use Laravel’s logging to capture output:

    $process->run();
    Log::debug('Process Output:', ['output' => $process->getOutput()]);
    Log::debug('Process Errors:', ['errors' => $process->getErrorOutput()]);
    
  5. Validate Commands Before Execution Sanitize user-provided commands to prevent injection:

    $command = escapeshellcmd($userInput);
    $process = new Process(explode(' ', $command));
    

Gotchas and Tips

Pitfalls

  1. Blocking Calls by Default

    • run() blocks execution until the process completes. For long-running tasks, use start() + isRunning() loop.
    • Fix: Use start() for async workflows and poll with isRunning().
  2. Output Buffering Issues

    • Some commands (e.g., ffmpeg, docker) buffer output. Use --no-buffer flags or stream incrementally.
    • Fix: For ffmpeg, use -loglevel info or pipe output to a file:
      $process = new Process(['ffmpeg', '-i', 'input.mp4', '-loglevel', 'info', 'output.mp4']);
      
  3. Environment Variables Not Merged

    • setEnv() replaces existing variables. Explicitly pass all required environment variables.
    • Fix: Merge with existing env:
      $process->setEnv(array_merge(
          $_ENV,
          ['CUSTOM_VAR' => 'value']
      ));
      
  4. Working Directory Permissions

    • Subprocesses inherit PHP’s umask. If writing files, ensure the directory is writable.
    • Fix: Use chmod or adjust umask:
      $process->setWorkingDirectory(storage_path('logs'));
      umask(0000); // Ensure full permissions
      
  5. No Built-in Retry Logic

    • The package doesn’t support retries. Implement custom retry logic for transient failures.
    • Fix: Use a loop with exponential backoff:
      $retries = 3;
      while ($retries--) {
          $process->run();
          if ($process->isSuccessful()) break;
          sleep(2 ** $retries); // Exponential backoff
      }
      
  6. Signal Handling Limitations

    • The package doesn’t expose SIGKILL or SIGTERM. Use terminate() for graceful shutdowns.
    • Fix: For forceful termination, use proc_terminate() (if available) or wrap in a pcntl_signal handler.
  7. Cross-Platform Path Issues

    • Paths like C:\path\to\file may fail on Unix. Normalize paths:
    • Fix: Use str_replace('\\', '/', $path) or DIRECTORY_SEPARATOR.

Debugging Tips

  1. Check Exit Codes Always log the exit code for debugging:

    $process->run();
    Log::debug('Exit Code:', ['code' => $process->getExitCode()]);
    
  2. Enable Verbose Output For troubleshooting, enable verbose logging:

    $process = new Process(['command', '--verbose']);
    
  3. Use strace or Process Explorer On Linux, use strace to debug process behavior:

    strace -f -o trace.log php artisan your:command
    

    On Windows, use Process Explorer to monitor child processes.

  4. Test with Simple Commands First Start with a simple command like echo "hello" to verify the package works before complex commands.


Extension Points

  1. Custom Process Builder Create a wrapper class for reusable process configurations:
    class GitProcess extends Process
    {
        public function __construct(string $repoPath)
        {
            parent::__construct(['git
    
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.
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
atriumphp/atrium
sandermuller/package-boost-laravel
sandermuller/boost-skills
redaxo/core
yusufgenc/filament-api-forge
l3aro/rating-star-for-filament
leek/filament-subtenant-scope