phpunit/php-invoker
phpunit/php-invoker is a small utility for safely invoking callables with time limits. Commonly used by PHPUnit to run tests and other code with a timeout, helping prevent hangs while keeping execution and error handling predictable.
Install as a dev dependency: composer require --dev phpunit/php-invoker. Its sole purpose is to safely execute callables (e.g., closures, invokables, or arrays like [$class, 'method']) with a strict timeout—commonly used in test suites to prevent hung processes from blocking CI runs. The most common first use case is wrapping potentially long-running test assertions:
use PHPUnit\Invoker\TimeoutInvocationException;
use PHPUnit\Invoker\Invoker;
$invoker = new Invoker;
try {
$invoker->invoke(fn() => $this->doSomethingSlow(), timeout: 1.5);
} catch (TimeoutInvocationException $e) {
$this->fail('Operation timed out');
}
Check src/Invoker.php for the core API—only two methods exist: invoke() and call()—so documentation fits in minutes.
try/catch around assertions in @after or @afterEach hooks to abort if cleanup logic hangs.pcntl_async_signals(true) and signal handlers to gracefully terminate timed-out operations (e.g., kill file watchers or sockets).setUp() or tearDown(); in Pest, wrap expectations in ensure() callbacks:
ensure(fn() => $this->doAsyncThing())->passesBefore(2.0);
(Note: Must manually handle timeouts—no automatic Pest integration exists.)ext-pcntl: The package depends on PCNTL for non-blocking timeouts. This fails silently on Windows (where pcntl_* functions are absent)—tests will timeout indefinitely unless you guard usage with function_exists('pcntl_async_signals').pcntl_async_signals(true)), timeouts may not interrupt cleanly. Always call this before invoking timed code.tick callbacks). Use declare(ticks=1) inside the callable for reliable interruption.Invoker and override handleTimeout()—but note the class is final in v7+, so modify via composition instead.$invoker->invoke($callable, 0.5, 'my-test-timeout'); (third param is a descriptive label logged on timeout).How can I help you explore Laravel packages today?