DEV Community

Cover image for Building a Command Line Tool with PHP and Symfony Console
Roberto B.
Roberto B.

Posted on

Building a Command Line Tool with PHP and Symfony Console

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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;
    }
}

Enter fullscreen mode Exit fullscreen mode

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 the src directory, we will set autoload.psr-4 in the composer.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) via setHelp() method;
  • 09 implementing the execute method with InputInterface and OutputInterface 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/"
        }
    }
}

Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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();

Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

Executing the new command

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
Enter fullscreen mode Exit fullscreen mode

Executing the new command line tool with the -h option

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/"
        }
    }
}

Enter fullscreen mode Exit fullscreen mode

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

See you on Twitter / X https://twitter.com/RmeetsH and / or Mastodon php social

🎉🎉🎉

Top comments (3)

Collapse
 
angelcamposm profile image
Angel Campos

good tutorial, thanks

Collapse
 
robertobutti profile image
Roberto B.

thank you for the feedback ✨

Collapse
 
trusted97 profile image
Gianluca Benucci

Great tutorial!