pmjones/auto-shell
AutoShell auto-maps CLI command names to PHP command classes in a namespace. It reflects a command’s main method to parse args/options (scalars or arrays), then returns an Exec to run. Zero dependencies—add a class and it becomes a command.
composer require pmjones/auto-shell
bin/console.php:
<?php
use AutoShell\Console;
require dirname(__DIR__) . '/vendor/autoload.php';
$console = Console::new(
namespace: 'App\\Cli\\Command',
directory: __DIR__ . '/../src/Cli/Command',
);
exit($console($_SERVER['argv']));
src/Cli/Command/Greet.php):
<?php
namespace App\Cli\Command;
class Greet
{
public function __invoke(string $name): int
{
echo "Hello, {$name}!\n";
return 0;
}
}
php bin/console.php greet Alice
__invoke() method.string $name).php bin/console.php greet Alice.src/Cli/Command (or custom directory).UserCreate → user:create).__invoke(), but can be customized (e.g., execute()).Options interface + #[Option] attributes.
class GreetOptions implements Options
{
public function __construct(
#[Option('f,force')]
public readonly ?bool $force
) {}
}
__invoke():
public function __invoke(GreetOptions $options, string $name): int
$console = Console::new(
namespace: 'App\\Cli\\Command',
directory: __DIR__ . '/../src/Cli/Command',
factory: fn(string $class) => $container->get($class),
);
#[Help] on the class.
#[Help("Greets a user.")]
class Greet {}
public function __invoke(
#[Help("Name to greet.")]
string $name
): int {}
Options parameters:
public function __invoke(
CommonOptions $common,
GreetOptions $options,
string $name
): int {}
0 for success, non-zero for errors (e.g., 1 for failures).throw new \RuntimeException() in __invoke() to propagate errors.Namespace/Directory Mismatch:
namespace and directory in Console::new() match your PSR-4 structure.namespace: 'App\\Cli\\Command' → directory: __DIR__ . '/../src/Cli/Command'.Option Conflicts:
-v) in multiple Options classes. Use OptionAlreadyDefined exception as a hint.Type Casting Quirks:
bool options default to true if present (even without a value). Use default: false to override:
#[Option('v,verbose', default: false)]
Variadic Parameters:
public function __invoke(string ...$names): int {}
Runs as: php bin/console.php greet Alice Bob Charlie.Help Text Parsing:
<<<HELP) must use HELP as the closing tag (case-sensitive).Check Command Discovery:
php bin/console.php to list available commands. If empty, verify:
directory path is correct.composer dump-autoload).Option Parsing Issues:
php bin/console.php help <command> to validate option definitions.#[Option] names (e.g., -v vs --verbose).Factory Debugging:
factory: fn(string $class) => new $class(), // Fallback to `new` if DI fails.
Custom Command Naming:
AutoShell\Shell and injecting it:
$shell = new CustomShell();
$console = Console::new(..., shell: $shell);
Custom Help Rendering:
help callable to Console::new():
help: fn(string $text) => echo "<pre>{$text}</pre>\n",
Pre/Post-Execution Hooks:
$console = fn(array $argv) => {
// Pre-execution logic
$code = $console($argv);
// Post-execution logic
return $code;
};
Console instance:
$console = Console::new(...);
// Reuse $console across requests (e.g., in a long-running process).
How can I help you explore Laravel packages today?