- What is Silly and how does it differ from Symfony Console?
- Silly is a lightweight CLI micro-framework built on top of Symfony Console. It adds closure-based command definitions with string signatures like greet [name] [--yell] and automatically injects arguments, options, OutputInterface, and container services into your callable. It is a thin ergonomics layer rather than a competing framework, so the underlying Symfony application and behavior stay the same.
- How do I install Silly in a PHP project with Composer?
- Run composer require mnapoli/silly. Then bootstrap a Silly\Application instance in a bin script or PHP file and register commands with $app->command(...) before calling $app->run(). No Laravel service provider or framework bootstrapping is required.
- Does Silly work with Laravel or Artisan?
- No, Silly is designed for standalone console binaries and does not integrate with Artisan. It extends Symfony\Console\Application, so it lives outside Laravel's kernel and command registry. For commands that need Eloquent, service providers, or Artisan namespaces, use native Artisan::command instead. Running both in one app leaves you with two command registries and two dependency injection conventions.
- How does dependency injection work in Silly with PHP-DI or Pimple?
- Silly supports PSR-11 containers, and the documentation covers both the PHP-DI edition and the Pimple edition. Type-hinted parameters in your command closure are resolved from the container, so you can receive services instead of reaching for globals. Parameter resolution is name-based, so renaming a parameter is a behavior change rather than a safe refactor.
- Which Symfony Console and PHP versions does Silly support?
- Silly tracks Symfony Console majors with dedicated releases, including 5.x via 1.7.2, 6.x via 1.8.0, 7.x via 1.9.0, and 8.x via 1.10.1. Check the release Notes or composer.json constraints for the exact PHP requirement, since each Symfony major raises the minimum PHP version. In general, pin the Silly release that matches the Symfony Console version already in your project.
- Can I test a Silly command without running it from the shell?
- Yes, because Silly commands are registered on a Symfony Console application, you can drive them with Symfony's CommandTester or ApplicationTester in PHPUnit. The closure body receives the same InputInterface, OutputInterface, and SymfonyStyle objects as a native Symfony command. Wrap the application in a test and assert on output, exit codes, and container-injected services.
- Is Silly safe to use in production CLI tooling?
- Silly is used in real tooling paths, with its README citing Bref and Laravel Valet as production users, and its release history is mostly compatibility fixes that indicate a low-churn maintenance posture. The main risks are that it is maintained by a single person and that command signatures are strings, so you get no static analysis or IDE discovery of wiring. Tooling breakage affects developer velocity rather than production traffic, so the blast radius is limited.
- How do I migrate a Silly command to a plain Symfony Console Command subclass?
- Subclass Symfony\Component\Console\Command\Command, move the closure body into execute(), and re-declare arguments and options in configure(). Because Silly\Application extends Symfony\Console\Application, the surrounding application wiring does not need to change. The exit cost is low, so budget roughly half a day per command in the unlikely event you need to leave.
- What are the alternatives to Silly for building PHP CLI apps?
- Symfony Console is the direct baseline, and Silly is essentially boilerplate removal on top of it. Laravel Zero is an option when you want a Laravel-like standalone CLI application, and native Artisan::command is the right choice when the commands belong inside a Laravel app. For a small ops script or Composer binary, plain Silly or a hand-rolled Symfony Console bootstrap is usually enough.
- How do I pass options and arguments to a Silly command closure?
- Define them in the signature string, for example greet [name] [--yell], and Silly maps them to closure parameters by name. Optional arguments use square brackets, options use the double-dash form, and OutputInterface or SymfonyStyle can be type-hinted as extra parameters. Silly also provides runCommand() for composing sub-commands from inside a command.