New in Symfony 4.1: Prepared commands

Contributed by
Hamza Amrouche
in #24763.

UPDATE: this feature was reverted in Pull Request #26372 until we can find a better implementation.


In Symfony 4.1 we improved the Process component to allow writing "prepared commands", a concept similar to prepared statements in SQL. The basic idea is to replace some parts of the command with placeholders whose values you provide later when actually running the command (or via environment variables):

1
2
3
4
use Symfony\Component\Process\Process;

$process = new Process('ls -lsa {{ path }}');
$process->run(null, ['path' => '/path/to/some/dir']);

Placeholders must follow the {{ placeholder_name }} syntax strictly, which has nothing to do with Twig, except for the coincidence in the use of brackets. If some placeholder value is missing when running the command, you'll get an InvalidArgumentException.

In addition to passing the placeholder values as the second argument of the run() method you can also pass them in the Process class constructor:

1
2
3
4
use Symfony\Component\Process\Process;

$process = new Process('ls -lsa {{ path }}', null, ['path' => '/path/to/some/dir']);
$process->run();

One of the best features of prepared commands is that placeholder values are escaped automatically, which makes your life as a developer easier and ensures that commands will always work as expected.

1
2
3
4
5
6
7
$process = new Process('mysqldump --user={{ db_user }} --password={{ db_pass }} {{ db_name }} > {{ db_backup_path }}');
$process->run(null, [
    'db_user' => getenv('DB_USER'),
    'db_password' => getenv('DB_PASS'),
    'db_name' => 'symfony',
    'db_backup_path' => '/var/backup/db-'.time().'.sql',
]);

If you don't like the idea of using placeholders in your commands for some reason, the Process component also allows since Symfony 3.3 to pass an array where the first element is the command to run and the rest of the array elements are its options and arguments, allowing you to build a complex command programmatically:

1
2
3
4
5
6
7
$process = new Process(array(
    'mysqldump',
    '--user='.getenv('DB_USER'),
    '--password='.getenv('DB_PASS'),
    $dbName,
));
$process->run();

Comments

Great new !

Thx Javier :)
Genius! This will make some of my commands a lot easier to read!
Thank you!
First they took away ProcessBuilder and now give Prepared commands. Well done...
@Gemorroj we're working on making some changes in this feature before the release of Symfony 4.1. Stay tuned because we'll update this article when those changes are ready.
@Javier Eguiluz yes, the feature is very interesting.
But, in my OPINION, at first it was necessary to release this feature, and then to remove `ProcessBuilder`.
Now I do not understand how to escape arguments. Probably, it is necessary to use native `escapeshellarg`. Which I don't think is good.
Thanks for this feature!
Following along a bit, the behaviour have changed. Now, it should be something like this on unix:

$process = new Process('ls -lsa "$path"', null, ['path' => '/path/to/some/dir']);


(See https://github.com/symfony/symfony/pull/26372)

Comments are closed.

To ensure that comments stay relevant, they are closed for old posts.