首页 > 解决方案 > PHP 命令行:以命令、子命令和参数的形式解析参数的有效方法

问题描述

我有一个脚本,应该如下调用:

script.php command subcommand --parameters parameter1="a" parameter2="b" parameterN="n"

例子:

script.php account backup import --parameters accont="UserA" backup_id=1

哪里command = 'account',subcommand = 'backup import'parameters = 'account="UserA"' backup_id=1

有没有一种有效的方法来解析所有案例而无需 4 级嵌套开关?

谢谢你。

--- 添加信息以完成问题 ---- 这就是它的外观:

// command stack
$commands = array('group', 'account', 'context');

// subcommand stack
$group_subcommands = array(
    'get',
    'list',
);
$account_subcommands = array(
    'add',
    'backup import',
    'backup list',
    'mfa add',
    'mfa del',
    'mfa list',
    'del',
    'get',
    'list',
    'register',
    'set',
    'antivirus get',
    'antivirus set',
);
$context_subcomands = array(
    'list',
);

每个子命令的示例唯一参数:

account add --parameters account="user1" name="John" last_name="Smith" --city="London"

强制= 帐户、姓名、姓氏
可选= 城市

account del --parameters accont="UserA"

强制= 帐户

标签: php

解决方案


您可以像这样存储您的命令/子命令:

$commands = ['group', 'account', 'context'];
$subCommands = [
  'group' => ['get', 'list'],
  'account' => ['add', 'backup import', 'backup list', 'mfa add', 'mfa del', 'mfa list', 'del', 'get', 'list', 'register', 'set', 'antivirus get', 'antivirus set'],
  'context' => ['list']
];

并使用以下功能:

function parseCommand(string $commandLine): array
{
  // Should ideally not be stored here, but somewhere like a config file, or at least in constants
  $commands = ['group', 'account', 'context'];
  $subCommands = [
    'group' => ['get', 'list'],
    'account' => ['add', 'backup import', 'backup list', 'mfa add', 'mfa del', 'mfa list', 'del', 'get', 'list', 'register', 'set', 'antivirus get', 'antivirus set'],
    'context' => ['list']
  ];

  if (!preg_match('/^(?<command>\w+)\s+(?<subCommand>[\w\s]+)(?:\s+--parameters\s+(?<paramsString>.*))?$/', $commandLine, $commandMatches)) {
    throw new \InvalidArgumentException('Invalid syntax.');
  }

  if (!in_array($commandMatches['command'], $commands, true)
      || !in_array($commandMatches['subCommand'], $subCommands[$commandMatches['command']], true)) {
    throw new \InvalidArgumentException('Invalid command and/or subcommand.');
  }

  $subCommandParams = [];
  if (!empty($commandMatches['paramsString'] && preg_match_all('/(?<name>\w+)=(?:"(?<value1>[^"]*)"|(?<value2>\w*))"?/', $commandMatches['paramsString'], $paramsMatches, PREG_SET_ORDER))) {
    foreach ($paramsMatches as $paramMatch) {
      $subCommandParams[$paramMatch['name']] = $paramMatch['value1'] ?: $paramMatch['value2'];
    }
  }

  return [$commandMatches['command'], $commandMatches['subCommand'], $subCommandParams];
}

我没有为可选/强制参数添加任何内容,但这应该很容易实现。

此外,理想情况下,您应该使用类来保存命令/子命令,并且可能还从函数返回专用对象(而不是数组)。

演示:https ://3v4l.org/aJopL


推荐阅读