Static Analysis
The package includes PHPStan rules that catch common mistakes at analysis time.
Lifecycle Method Parameters
When a lifecycle method declares parameters, they are resolved from the arguments you passed to execute(). The rule catches mismatches between the two.
Type Match, Name Mismatch
When a lifecycle method declares a parameter with the right type but a different name, the container can't match it to the dispatched argument. For Eloquent models this means a new empty instance instead of the one you queued:
class ProcessOrder
{
use QueueableExecutable;
public function execute(Order $order): void
{
/* ... */
}
// BUG: $o instead of $order
public function displayName(Order $o): string
{
return "Process order #{$o->reference}"; // $o->reference is null!
}
}PHPStan will flag this with: Parameter $o on method displayName() has type Order matching execute() parameter $order — did you mean $order?
Other Cases
class ProcessOrder
{
use QueueableExecutable;
public function execute(Order $order): void
{
/* ... */
}
// Name matches, type differs. Likely a typo
public function tags(string $order): array
{
/* ... */
}
}PHPStan will flag this with: Parameter $order on method tags() has type string but execute() declares $order as Order
class ProcessOrder
{
use QueueableExecutable;
public function execute(Order $order): void
{
/* ... */
}
// Parameter not on execute() at all. Dead parameter
public function uniqueId(string $tenant): string
{
/* ... */
}
}PHPStan will flag this with: Parameter $tenant on method uniqueId() is not declared on execute()
class ProcessOrder
{
use QueueableExecutable;
public function execute(Order $order): void
{
/* ... */
}
// failed() must have Throwable as first parameter
public function failed(Order $order): void
{
/* ... */
}
}PHPStan will flag this with: Method failed() must declare Throwable as its first parameter, found Order $order
class ProcessOrder
{
use QueueableExecutable;
public function execute(Order $order): void
{
/* ... */
}
// configure() must have QueueableConfig as first parameter
public function configure(Order $order): void
{
/* ... */
}
}PHPStan will flag this with: Method configure() must declare QueueableConfig as its first parameter, found Order $order
Checked Lifecycle Methods
The rule checks all lifecycle methods: configure, backoff, displayName, retryUntil, tries, uniqueFor, uniqueId, tags, middleware, failed, uniqueVia.
Suppressing the Rule
// @phpstan-ignore executable.paramMismatch
public function displayName(Order $o): stringOr globally in phpstan.neon:
parameters:
ignoreErrors:
- identifier: executable.paramMismatchDirect execute() Calls
Calling ->execute() directly on an executable instance bypasses the execution pipeline. Transactions, conditional execution, and after-response dispatch won't work.
$action = app(ProcessOrder::class);
$action->execute($order); PHPStan will flag this with: Calling execute() directly bypasses the execution pipeline. Use $action->sync()->execute() instead.
Suppressing the Rule
// @phpstan-ignore executable.directExecuteCall
$action->execute($order);Or globally in phpstan.neon:
parameters:
ignoreErrors:
- identifier: executable.directExecuteCallQueue Features on Sync Executables
Classes that use the Executable trait run synchronously. Queue-related properties, lifecycle methods, interfaces, and attributes only take effect with the QueueableExecutable trait. The rule flags these dead declarations so you can remove them or switch to QueueableExecutable.
Queue Properties
class ProcessOrder
{
use Executable;
public int $tries = 3;
public int $timeout = 30;
public function execute(Order $order): void
{
/* ... */
}
}PHPStan will flag this with: Class ProcessOrder uses Executable (sync-only) but declares queue property $tries. This has no effect without the QueueableExecutable trait.
Lifecycle Methods
class ProcessOrder
{
use Executable;
public function execute(Order $order): void
{
/* ... */
}
public function tags(): array
{
return ["order"];
}
}PHPStan will flag this with: Class ProcessOrder uses Executable (sync-only) but declares queue lifecycle method tags(). This has no effect without the QueueableExecutable trait.
Queue Interfaces
use Illuminate\Contracts\Queue\ShouldBeEncrypted;
class ProcessOrder implements ShouldBeEncrypted
{
use Executable;
public function execute(Order $order): void
{
/* ... */
}
}PHPStan will flag this with: Class ProcessOrder uses Executable (sync-only) but implements ShouldBeEncrypted. This has no effect without the QueueableExecutable trait.
Queue Attributes
use Illuminate\Queue\Attributes\WithoutRelations;
#[WithoutRelations]
class ProcessOrder
{
use Executable;
public function execute(Order $order): void
{
/* ... */
}
}PHPStan will flag this with: Class ProcessOrder uses Executable (sync-only) but has attribute #[WithoutRelations]. This has no effect without the QueueableExecutable trait.
Suppressing the Rule
// @phpstan-ignore executable.syncWithQueueFeatures
public int $tries = 3;Or globally in phpstan.neon:
parameters:
ignoreErrors:
- identifier: executable.syncWithQueueFeatures