nette/command-line 问题修复 & 功能扩展

解决BUG、新增功能、兼容多环境部署,快速响应你的开发需求

邮箱:yvsm@zunyunkeji.com | QQ:316430983 | 微信:yvsm316

nette/command-line

Composer 安装命令:

composer require nette/command-line

包简介

Nette Command Line: options and arguments parser.

README 文档

README

Downloads this Month Tests Coverage Status Latest Stable Version License

A lightweight library for building command-line applications in PHP. It provides:

  • Argument parsing with switches, options, and positional arguments
  • Colorful terminal output with ANSI support

Install it using Composer:

composer require nette/command-line

It requires PHP version 8.2 and supports PHP up to 8.5.

If you like Nette, please make a donation now. Thank you!

Parsing Command-Line Arguments

Every CLI script needs to handle arguments like --verbose, -o output.txt, or plain file names. The Parser class offers the fastest way to get started: just write your help text and let the parser extract option definitions from it:

use Nette\CommandLine\Parser;

$parser = new Parser;
$parser->addFromHelp('
	-h, --help              Show this help
	-v, --verbose           Enable verbose mode
	-o, --output <file>     Output file
	-f, --format [type]     Output format (default: json)
	-I, --include <path>... Include paths
	--dry-run               Show what would be done
');

$args = $parser->parse();

That's it. The parser understands that --verbose is a switch, --output requires a value, --format has an optional value with json as fallback. Your help text stays in sync with actual option definitions.

The parse() method returns an associative array. Keys match option names exactly as defined, including the dashes:

[
	'--help' => true,         // or null if not used
	'--verbose' => null,
	'--output' => 'file.txt', // or null if not used
	'--format' => 'json',     // fallback from (default: json)
	'--include' => ['src', 'lib'],
	'--dry-run' => null,
]

By default, parse() reads from $_SERVER['argv']. You can pass a custom array for testing:

$args = $parser->parse(['--verbose', '-o', 'out.txt']);

Help Text Syntax

The parser extracts option definitions from formatted help text:

Syntax Meaning
--verbose Switch (no value)
-v, --verbose Switch with short alias
--output <file> Option with required value
--format [type] Option with optional value
(default: json) Sets fallback value
<path>... Repeatable option

Each line defines one option. Option names must be separated from descriptions by at least two spaces.

Additional Configuration

Some settings can't be expressed in help text. Pass an array as the second parameter, keyed by option name:

$parser->addFromHelp('
	-c, --config <file>   Configuration file
	-I, --include <path>  Include path
	-n, --count <num>     Number of iterations
', [
	'--config' => [
		Parser::RealPath => true,
	],
	'--include' => [
		Parser::Repeatable => true,
	],
	'--count' => [
		Parser::Normalizer => fn($v) => (int) $v,
	],
]);

Available keys:

Key Description
Parser::Repeatable Collect multiple values into array
Parser::RealPath Validate file exists and resolve to absolute path
Parser::Normalizer Transform function fn($value) => ...
Parser::Default Fallback value (same as (default: x) in help text)
Parser::Enum Array of allowed values

Fluent API

When you need more control over option definitions, use the fluent API with addSwitch(), addOption(), and addArgument() methods. This approach gives you access to all features including normalizers, enums, and precise control over each parameter:

use Nette\CommandLine\Parser;

$parser = new Parser;
$parser
	->addSwitch('--verbose', '-v')
	->addOption('--output', '-o')
	->addArgument('file');

$args = $parser->parse();

By default, parse() reads from $_SERVER['argv']. You can pass a custom array for testing:

$args = $parser->parse(['--verbose', '-o', 'out.txt', 'input.txt']);

Switches, Options, and Arguments

There are three types of command-line inputs:

Switches are flags without values, like --verbose or -v. They parse as true when present, null when absent:

$parser->addSwitch('--verbose', '-v');
// --verbose  → true
// -v         → true
// (not used) → null

Options accept values, like --output file.txt. The value can be separated by space or =:

$parser->addOption('--output', '-o');
// --output file.txt    → 'file.txt'
// --output=file.txt    → 'file.txt'
// -o file.txt          → 'file.txt'
// --output             → throws exception (value required)
// (not used)           → null

Note that the option itself is always optional - not using it returns null. However, when used, the value is required by default. Set optionalValue: true to allow the option without a value (parses as true):

$parser->addOption('--format', '-f', optionalValue: true);
// --format json        → 'json'
// --format             → true
// (not used)           → null

When the same option is used multiple times without repeatable: true, the last value wins:

$parser->addOption('--output', '-o');
// -o first.txt -o second.txt  → 'second.txt'

Arguments are positional values without dashes. By default they are required. Set optional: true to make them optional:

$parser->addArgument('input');
// script.php file.txt  → 'file.txt'
// (not used)           → throws exception

$parser->addArgument('output', optional: true);
// (not used)           → null

$parser->addArgument('output', optional: true, fallback: 'out.txt');
// (not used)           → 'out.txt'

Use fallback to specify the value when an option or argument is not provided. For options with optionalValue: true, note that using the option without a value still parses as true, while the fallback is used only when the option is not present at all:

$parser->addOption('--format', '-f', optionalValue: true, fallback: 'json');
// --format xml  → 'xml'
// --format      → true (option used without value)
// (not used)    → 'json' (fallback)

Arguments can appear anywhere on the command line - they don't have to come after options:

// all of these are equivalent:
// script.php --verbose input.txt
// script.php input.txt --verbose

Restricting Values with Enum

Limit accepted values to a specific set:

$parser->addOption('--format', '-f', enum: ['json', 'xml', 'csv']);
// --format yaml  → throws "Value of option --format must be json, or xml, or csv."

Repeatable Options

Set repeatable: true to collect multiple values into an array:

$parser->addOption('--include', '-I', repeatable: true);
// -I src -I lib  → ['src', 'lib']
// (not used)     → []

$parser->addArgument('files', optional: true, repeatable: true);
// a.txt b.txt    → ['a.txt', 'b.txt']

Transforming Values

Use normalizer to transform parsed values:

$parser->addOption('--count', normalizer: fn($v) => (int) $v);
// --count 42  → 42 (integer)

For file path validation, use the built-in normalizeRealPath:

$parser->addOption('--config', normalizer: Parser::normalizeRealPath(...));
// --config app.ini     → '/full/path/to/app.ini'
// --config missing.ini → throws "File path 'missing.ini' not found."

Mixing Both Approaches

You can combine addFromHelp() with fluent methods when you need normalizers for some options:

$parser
	->addFromHelp('
		-v, --verbose  Enable verbose mode
		-q, --quiet    Suppress output
	')
	->addOption('--config', '-c', normalizer: Parser::normalizeRealPath(...),
		description: 'Configuration file')
	->addArgument('input', description: 'Input file');

Error Handling

The parser throws \Exception for invalid input:

use Nette\CommandLine\Parser;

$parser = new Parser;
$parser
	->addOption('--output', '-o')
	->addArgument('file');

try {
	$args = $parser->parse();
} catch (\Exception $e) {
	fwrite(STDERR, "Error: {$e->getMessage()}\n");
	exit(1);
}

Common error messages:

Error Cause
Option --output requires argument. Option used without required value
Unknown option --foo. Unrecognized option
Missing required argument <file>. Required argument not provided
Unexpected parameter foo. Extra positional argument
Value of option --format must be json, or xml. Value not in enum

Use isEmpty() to check if no command-line arguments were provided (i.e., user ran just script.php with nothing after it):

if ($parser->isEmpty()) {
	$parser->help();
	exit;
}

Handling --help and --version

When your script has required arguments, running script.php --help would normally fail because the required argument is missing. Use parseOnly() to check for info options first:

$parser = new Parser;
$parser
	->addSwitch('--help', '-h')
	->addSwitch('--version', '-V')
	->addArgument('input');  // required

// First, check info options (no validation, no exceptions)
$info = $parser->parseOnly(['--help', '--version']);

if ($info['--help']) {
	$parser->help();
	exit;
}

if ($info['--version']) {
	echo "1.0.0\n";
	exit;
}

// Now do full parsing with validation
$args = $parser->parse();

The parseOnly() method:

  • Parses only the specified options, ignoring everything else
  • Respects aliases (-h--help)
  • Never throws exceptions
  • Returns null for options that weren't used

Complete Example

Here's a real-world file converter script combining Parser and Console:

#!/usr/bin/env php
<?php
use Nette\CommandLine\Parser;

require __DIR__ . '/vendor/autoload.php';

$parser = new Parser;
$parser
	->addFromHelp('
		-h, --help           Show this help
		-v, --verbose        Show detailed output
		-n, --dry-run        Show what would be done
		-f, --format [type]  Output format (default: json)
		-o, --output <file>  Output file
	', [
		'--format' => [
			Parser::Enum => ['json', 'xml', 'csv'],
		],
	])
	->addArgument('input', normalizer: Parser::normalizeRealPath(...));

// Handle --help before validation (avoids "missing argument" error)
if ($parser->isEmpty() || $parser->parseOnly(['--help'])['--help']) {
	echo "Usage: convert [options] <input>\n\n";
	$parser->help();
	exit;
}

try {
	$args = $parser->parse();
} catch (\Exception $e) {
	fwrite(STDERR, "Error: {$e->getMessage()}\n");
	exit(1);
}

if ($args['--verbose']) {
	echo "Converting {$args['input']} to {$args['--format']}...\n";
}

if ($args['--dry-run']) {
	echo "Dry run: No changes made.\n";
	exit;
}

// ... conversion logic here ...

echo "Done!\n";

The script accepts commands like:

  • convert input.txt - convert with defaults
  • convert -v --format xml input.txt - verbose, XML format
  • convert -o result.txt input.txt - specify output file
  • convert --help - show help (works even without input file)

nette/command-line 适用场景与选型建议

nette/command-line 是一款 基于 PHP 开发的 Composer 扩展包,目前已累计 1.75M 次下载、GitHub Stars 达 37, 最近一次更新时间为 2014 年 08 月 22 日, 在 PHP 生态内属于活跃度较高的组件。

它主要适用于以下技术方向: 「nette」 「cmd」 「cmd-line」 等业务场景。在实际项目中,围绕这些方向常见需要落地的问题包括:接口对接、性能调优、并发安全、与既有框架(Laravel / ThinkPHP / Yii / Webman 等)的兼容适配,以及生产环境的日志埋点与稳定性保障。

我们在过去多个企业项目中使用过 nette/command-line 或与其功能相近的方案,如果你在选型或落地过程中遇到问题,例如 版本兼容、二次改造、私有化封装、与内部系统对接、生产 BUG 排查,欢迎联系我们协助评估。

围绕 nette/command-line 我们能提供哪些服务?
定制开发 / 二次开发

基于 nette/command-line 在你已有业务上做功能扩展、字段裁剪、UI 适配、与内部账号 / 权限 / 日志系统的深度对接。

BUG 修复 & 性能优化

线上偶发问题、内存泄漏、慢查询、并发异常等排查修复;针对高流量场景做缓存、队列、索引层面的调优。

项目外包 & 长期维护

承接完整的项目从需求 → 设计 → 开发 → 上线 → 长期运维;也可按月提供技术保姆服务。

yvsm@zunyunkeji.com QQ:316430983 微信:yvsm316 西安尊云信息科技 · 专注 PHP / Go / 分布式系统研发

统计信息

  • 总下载量: 1.75M
  • 月度下载量: 0
  • 日度下载量: 0
  • 收藏数: 38
  • 点击次数: 26
  • 依赖项目数: 13
  • 推荐数: 0

GitHub 信息

  • Stars: 37
  • Watchers: 19
  • Forks: 5
  • 开发语言: PHP

其他信息

  • 授权协议: BSD-3-Clause
  • 更新时间: 2014-08-22