我正在编写一个 PHP CLI 工具。工具有许多可用的命令行选项。这将是一堂课。我将加载一个实例并使用传入的所有参数运行命令。
捕获进展中的信息消息以及捕获错误并停止错误并将输出输出到屏幕的最佳方法是什么?
理想的 PHP CLI 示例是什么?
我更喜欢使用一种观察者模式进行处理,并将错误处理留给控制台应用程序:
class ExampleService
{
/**
* @var array
*/
private $params;
public function __construct(array $params)
{
$this->params = $params;
}
/**
* @param callable|null $listener
*/
public function execute(callable $listener = null)
{
foreach (['long', 'term', 'loop'] as $item) {
// do complex stuff
$listener && $listener($item);
}
}
}
require_once __DIR__ . '/vendor/autoload.php';
use Symfony\Component\Console\Application;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
$app = new Application;
$app->add($command = new Command('example'));
$command->addOption('opt1');
$command->addArgument('arg1');
$command->setCode(function(InputInterface $input, OutputInterface $output) {
$service = new ExampleService($input->getOptions() + $input->getArguments());
$service->execute(function($messages) use($output){
$output->writeln($messages);
});
});
$app->run();
我使用这样的模板(对于足够简单的控制台脚本):
$inputFile = null;
$outputFile = null;
try {
// Checking command-line arguments
if (1 === $argc) {
throw new Exception('Missing input file path.');
}
$inputFilePath = $argv[1];
if (!file_exists($inputFilePath) || !is_readable($inputFilePath)) {
throw new Exception('Input file does not exist or cannot be read.');
}
$inputFile = fopen($inputFilePath, 'r');
if (2 < $argc) {
$outputFilePath = $argv[2];
if (!is_writable($outputFilePath)) {
throw new Exception('Cannot write to output file.');
}
$outputFile = fopen($outputFilePath, 'w');
} else {
$outputFile = STDOUT;
}
// Do main process (reading data, processing, writing output data)
} catch (Exception $e) {
// Show usage info, output error message
fputs(STDERR, sprintf('USAGE: php %s inputFilePath [outputFilePath]', $argv[0]) . PHP_EOL);
fputs(STDERR, 'ERROR: ' . $e->getMessage() . PHP_EOL);
}
// Free resources
if ($inputFile) {
fclose($inputFile);
}
if ($outputFile) {
fclose($outputFile);
}
如果你使用 Symfony,有一个进度条组件非常有用。它可以帮助您在 CLI 输出中显示一个非常大的循环的进度。但是,如果您从自动进程(例如 cron 作业)运行该命令,那么就没那么有用了。它不推送日志。
Symfony 命令还允许轻松写入 CLI 输出。
至于捕获错误,我认为你应该使用try/catch aproch。