我使用 Symfony Process 编写了一个要求密码的命令:
$validPassword = false;
do {
$question = new Question('Enter password: ');
$question->setHidden(true);
$question->setHiddenFallback(false);
$password = $questionHelper->ask($input, $output, $question);
if ($password === null || trim($password) === '') {
continue;
}
try {
doSomeTaskThatRequiresThePassword($password);
$validPassword = true;
} catch (\RuntimeException $e) {
$output->writeln(
sprintf(
'<error>Error: %s</error>',
$e->getMessage()
)
);
}
} while (!$validPassword);
命令是从独立文件调用的:
#!/usr/bin/env php
<?php
require __DIR__ . '/vendor/autoload.php';
use App\MyCommand;
(new MyCommand())->run();
此外,由于我使用的是 Windows,所以我有一个小包装:
@ECHO OFF
setlocal DISABLEDELAYEDEXPANSION
SET BIN_TARGET=%~dp0my-command
php "%BIN_TARGET%" %*
以上所有内容都非常有魅力。
我使用 Composer 来运行所有项目实用程序和自定义命令,因此我对此尝试了相同的操作:
{
"scripts": {
"lint": [
"@phpcs"
],
"phpcs": "phpcs",
"phpcbf": "phpcbf",
"my-command": "my-command with some parameters --verbose --blah blah"
}
}
问题是执行并没有在
$questionHelper->ask()
处停止。当 do/while 使用空密码进行时,我只是进入无限循环。使用 PowerShell 或命令提示符,或者跳过 *.bat 包装并将命令定义为 "php my-command"
,都没有任何区别。
C:\Projects\Foo>composer my-command
> php my-command with some parameters --verbose --blah blah
Enter password:
Enter password:
Enter password:
Enter password:
Enter password:
[…]
这是 Composer 的固有限制还是我需要调整一些内容才能运行交互式命令?
Composer 似乎仅在 Linux 上支持交互式脚本(自 Composer/2.7.9),因为它需要 TTY 模式,而 PHP 实现的 Win32 API 不支持该模式。
但是,它为 Symfony 进程提供了 一流的支持:
从 Composer 2.5 开始,脚本也可以是 Symfony 控制台命令 类,它允许您轻松运行它们,包括传递 选项。但是,不建议在处理事件时这样做。
因此您可以完全删除包装器脚本并直接调用命令类:
{
"scripts": {
"my-command": "\\App\\MyCommand"
}
}
不幸的是,这不允许额外的参数,除非每次都手动提供:
PS C:\> composer my-command with some parameters --verbose --blah blah
令人惊讶的是,如果间接调用该类,您可以预定义其他参数,因此并不是真的不支持定义参数,只是没有人想到这种特定的语法:
{
"scripts": {
"my-command-class": "\\App\\MyCommand",
"my-command": "@my-command-class with some parameters --verbose --blah blah"
}
}
PS C:\> composer my-command