Command line tools are a powerful way to automate processes, manage tasks, and enhance your development workflow. In this article, we'll explore how to create a simple command line tool in PHP using the Symfony Console (symfony/console
) package.
Why Symfony Console?
Command-line applications are a cornerstone of automation, providing developers a versatile and efficient way to interact with their systems. Although it is possible to create command-line tools using plain PHP, the Symfony Console library enhances the development process by providing a structured, feature-rich environment. This short article will explore the importance of using the Symfony Console package. It will highlight its capabilities, such as automatically generating help, handling input with options and arguments, defining defaults, and providing a clear structure with command classes.
Automatic Help Generation
One significant advantage of Symfony Console is its ability to automatically generate help for your commands. Symfony Console can produce comprehensive and user-friendly help documentation by defining descriptions, options, and arguments. This feature reduces manual documentation efforts and ensures users can easily understand and utilize your command line tool.
Input Management with Options and Arguments
Symfony Console simplifies user input handling by providing a well-defined system for options and arguments. Options are flags that modify the behavior of a command, while arguments are values (string) passed to the command. With Symfony Console, you can easily specify the expected inputs, making your commands more intuitive and user-friendly.
Consistency through docopt conventions
Symfony Console closely follows the well-established docopt conventions. Docopt, based on longstanding conventions from help messages and man pages, ensures a consistent and intuitive interface for describing a program's interface. Symfony Console's adherence to docopt conventions guarantees that your command line tools maintain a standardized and predictable user experience, simplifying development and user interaction.
Default Values and Input Validation
The ability to define default values for options and arguments is crucial for maintaining flexibility while ensuring a consistent user experience. Symfony Console allows you to set default values effortlessly, reducing the need for repetitive code. Additionally, the library provides input validation, helping you handle user input gracefully and prevent unexpected errors.
Convenient Helper Functions for User Input and Output
Symfony Console offers a robust set of helper functions designed to facilitate the management of user input and output, providing seamless interaction with the tool during execution. For instance, these helpers enable features such as requesting additional information from the user. From formatting and coloring output to prompting users for input, these utilities significantly improve the overall user experience and contribute to streamlining the development process.
Structured and Class-Based Commands
Symfony Console encourages a clean and organized structure for your command line applications. Commands are defined as classes, allowing for modularity, code reuse, and testability. This structured approach makes it easier to maintain and extend your command line tools as your project evolves.
Installation
To get started, you'll need to install the Symfony Console package using Composer. Open your terminal and run the following command:
composer require symfony/console
Creating Your First Command
Let's create a simple HelloWorldCommand
as a quick example.
We want to create a src/Commands folder to store all the commands we want to build. Let's start with the first, creating the new PHP file (e.g., HelloWorldCommand.php
) in the src/Commands
directory:
mkdir -p src/Commands
And creating the new file src/Commands/HelloWorldCommand.php
, adding the following code:
<?php
// 01 giving a name space
//Remember to set MyExample in the autoload.psr-4 in composer.json
namespace MyExample\Commands;
// 02 Importing the Command base class
use Symfony\Component\Console\Command\Command;
// 03 Importing the input/output interfaces
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
// 04 Defining the class extending the Command base class
class HelloWorldCommand extends Command
{
// 05 Implementing the configure method
protected function configure()
{
$this
// 06 defining the command name
->setName('hello')
// 07 defining the description of the command
->setDescription('Prints Hello')
// 08 defining the help (shown with -h option)
->setHelp('This command prints a simple greeting.');
}
// 09 implementing the execute method
protected function execute(InputInterface $input, OutputInterface $output): int
{
// 10 using the Output for writing something
$output->writeln("Hello, " . get_current_user() . "!");
$output->writeln("It's " . date("l"));
// 11 returning the success status
return Command::SUCCESS;
}
}
With the HelloWorldCommand.php
file, we created a very simple class that extends the Command
class provided by the Symfony Console package. Walking through the code, we:
-
01 setting a namespace with
namespace MyExample\Commands;
for allowing the autoload mechanism to load our new classes under thesrc
directory, we will setautoload.psr-4
in thecomposer.json
file later; -
02 Importing the
Command
base class provided by the Symfony Console package; - 03 Importing the input / output interfaces provided by the Symfony Console package;
-
04 Defining the HelloWorldCommand class extending the
Command
base class provided by the Symfony Console package; -
05 Implementing the
configure
method where you can set some properties of your command like the name, the description, the help message etc; -
06 defining the command name via
setName()
method; -
07 defining the command's description via
setDescription()
method; -
08 defining the help message (shown with
-h
option) viasetHelp()
method; -
09 implementing the execute method with
InputInterface
andOutputInterface
parameters, returning an integer; -
10 printing a message using the Output via the
$output->writeln()
method; -
11 returning the status with
Command::SUCCESS
.
Setting autoload in your composer.json file
Because we are starting to build all the sources and the class from scratch, we need to set up the autoload configuration correctly in our composer.json file. Because we are using the MyExample
namespace, and we want to load automatically the classes stored in the src/
directory when a class with MyExample
namespace is used, we can define autoload as "MyExample\\": "src/"
, here we have the composer.json
file:
{
"require": {
"symfony/console": "^7.0"
},
"autoload": {
"psr-4": {
"MyExample\\": "src/"
}
}
}
When you change some configuration with the autoloader, I suggest you run the dump-autoload
composer command for dumping and re-generating the autoloader configuration:
composer dump-autoload
Now we can create the main command file for laucnihng correctly the Command class we created.
Creating the command line script
Now, let's create the main file that will run our command. Create a file (e.g., my-cli
) and add the following code:
#!/usr/bin/env php
<?php
use MyExample\Commands\HelloWorldCommand;
use Symfony\Component\Console\Application;
if (file_exists(__DIR__ . '/../../autoload.php')) {
require __DIR__ . '/../../autoload.php';
} else {
require __DIR__ . '/vendor/autoload.php';
}
/**
* Start the console application.
*/
$app = new Application('Hello World', '1.0.0');
//$app->setDefaultCommand("hello");
$app->add(new HelloWorldCommand());
// $app->add(new AnotherCommand());
$app->run();
The "require the autoload" file will bootstrap the classes/packages autoloader correctly.
Then, you can initialize the application with new Application
, setting the application's name and version.
Then, you can add all the commands you had implemented. In our example, we just created the HelloWorldCommand
class, and then you can run the command via $app->run();
.
Executing the command line
Now, if you named your main file as my-cli
, you can launch your new command with php
(the interpreter) , my-cli
the name of your main script and hello
the name of your command class:
php my-cli hello
You can also use the -h
option to see the help generated by the Symfony Console using the information you set in the configure method:
php my-cli hello -h
A bonus tip
If you want to publish your command line tool on Packagist you can define the bin
option in the composer.json
file.
{
"require": {
"symfony/console": "^7.0"
},
"bin": [
"bin/my-cli"
],
"autoload": {
"psr-4": {
"MyExample\\": "src/"
}
}
}
With the bin
option, Composer installs the package executable files (my-cli
) in the vendor/bin
directory for all projects that depend on that specific package. This method conveniently brings out valuable scripts that might otherwise remain hidden in the depths of the vendor/bin
directory.
Wrapping up
With Symfony Console package, creating command line applications/tools in PHP becomes a breeze. This quick start article provides a foundation for building your own command line tools efficiently. Explore Symfony Console's documentation for more advanced features and possibilities. Happy coding!
References
- The Symfony Console component: https://symfony.com/doc/current/components/console.html
- The docopt Command-line interface description language: http://docopt.org/
- Composer autoloading: https://getcomposer.org/doc/01-basic-usage.md#autoloading
- Setting a vendor binary: https://getcomposer.org/doc/articles/vendor-binaries.md
See you on Twitter / X https://twitter.com/RmeetsH and / or Mastodon php social
ššš
Top comments (3)
good tutorial, thanks
thank you for the feedback āØ
Great tutorial!