Console_CommandLine
패키지는 명령행 인자를 파싱하는 PEAR 라이브러리입니다. 컴포져를 이용해서 설치하려면 composer.json
에 다음 내용을 알맞은 위치에 추가하면 됩니다.
1
2
3
4
5
6
7
8
9
10
11
|
{
"repositories": [
{
"type": "pear",
"url": "http://pear.php.net"
}
],
"require": {
"pear-pear.php.net/Console_CommandLine": "*"
}
}
|
기본 사용법#
Console_CommandLine
을 사용하기 위해서는 Console_CommandLine
인스턴스를 생성한 후에, addOption()
또는 addArgument()
메소드로 옵션이나 인자에 대한 명세를 설정한 후 parse()
메소드를 통해 파싱을 하면 됩니다. 이 과정 중에 명세에 맞지 않는 인자를 발견하면 예외가 발생합니다. 이 때 발생한 예외를 잡아서 적절한 사용법 안내를 화면에 출력합니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
<?php
require 'vendor/autoload.php';
$parser = new Console_CommandLine(['name' =>'hello']);
$parser->description = 'Hello Program';
$parser->version = '1.0.0';
try {
$result = $parser->parse();
echo 'Hello.'.PHP_EOL;
} catch (Exception $e) {
$parser->displayError($e->getMessage());
}
|
우선 컴포져를 통해서 Console_CommandLine
패키지를 읽어들이기 위해 vendor/autoload.php
를 불러들입니다. 그 다음 Console_CommandLine
인스턴스를 생성하면서 프로그램 이름을 “hello"로 설정합니다. 프로그램 설명은 “Hello Program"으로, 버전은 “1.0.0"으로 설정합니다. 설정은 인스턴스를 생성하면서 매개변수로 전달하여 할 수도 있고, 생성 후 프로퍼티에 값을 대입하여 할 수도 있습니다.
1
2
3
4
5
6
7
8
9
|
php example01.php -h
Hello Program
Usage:
hello [options]
Options:
-h, --help show this help message and exit
-v, --version show the program version and exit
|
기본적으로 도움말(-h, –help) 옵션을 제공합니다. 버전(-v, –version) 옵션은 버전을 설정한 경우에만 사용 가능합니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
<?php
require 'vendor/autoload.php';
$parser = new Console_CommandLine(['name' =>'hello']);
$parser->description = 'Hello Program';
$parser->version = '1.0.0';
$parser->addOption(
'korean',
[
'short_name' => '-k',
'long_name' => '--korean',
'description' => '한국어',
'action' => 'StoreTrue'
]
);
try {
$result = $parser->parse();
if (isset($result->options['korean']) && $result->options['korean'] == true) {
$hello = '안녕하세요.';
} else {
$hello = 'Hello.';
}
echo $hello.PHP_EOL;
} catch (Exception $e) {
$parser->displayError($e->getMessage());
}
|
이번에는 인사를 한국어로 출력하는 옵션(-k, –korean)을 추가했습니다. addOption()
메소드를 이용해 옵션 이름은 “korean"으로 하고, 짧은 옵션은 -k
, 긴 옵션은 --korean
으로 설정했습니다. description
은 옵션에 대한 설명으로 도움말(-h) 옵션 사용시 출력됩니다. action
은 옵션을 지정했을 때 어떻게 처리하는가에 대한 값으로, 여기서는 -k
옵션을 지정하면 true
값으로 설정하도록 했습니다. (StoreTrue
)
옵션값은 options
배열에 옵션 이름을 첨자로 사용해서 확인 할 수 있습니다. 옵션을 사용하지 않은 경우 null
값이 됩니다. 여기서는 StoreTrue
액션으로 지정했으므로, 한국어 옵션을 사용한 경우 true
값이 됩니다.
1
2
3
4
5
6
7
8
9
10
|
php example-2.php -h
Hello Program
Usage:
hello [options]
Options:
-k, --korean 한국어
-h, --help show this help message and exit
-v, --version show the program version and exit
|
도움말을 출력 해보면 추가한 한국어 옵션을 확인 할 수 있습니다.
1
|
php example-2.php --korean
|
이제 한국어 옵션(-k
, --korean
)을 사용하면 한국어로 인사말을 출력합니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
|
<?php
require 'vendor/autoload.php';
$parser = new Console_CommandLine(['name' =>'hello']);
$parser->description = 'Hello Program';
$parser->version = '1.0.0';
$parser->addOption(
'korean',
[
'short_name' => '-k',
'long_name' => '--korean',
'description' => '한국어',
'help_name' => 'KOREAN',
'action' => 'StoreTrue'
]
);
$parser->addArgument(
'name',
[
'multiple' => true,
'description' => '이름',
'help_name' => 'NAME'
]
);
try {
$result = $parser->parse();
if (isset($result->options['korean']) && $result->options['korean'] == true) {
$hello = '안녕하세요.';
} else {
$hello = 'Hello.';
}
foreach ($result->args['name'] as $name) {
echo "{$hello} {$name}.".PHP_EOL;
}
} catch (Exception $e) {
$parser->displayError($e->getMessage());
}
|
이름을 명령행 인자로 받아 인사를 하도록 해보았습니다. addArgument()
메소드를 통해 명령행 인자를 추가 할 수 있습니다. 명령행 인자 이름은 “name"으로, description
은 “이름"으로, help_name
은 “NAME"으로 설정했습니다. description
과 help_name
은 도움말 화면을 통해 출력됩니다.
multiple
을 true
로 설정하면, 인자를 여럿 받을 수 있습니다. 도움말에는 help_name
뒤에 숫자를 붙이고 말줄임표를 뒤에 덧붙여서 인자를 여럿 사용 할 수 있다는 것을 보여줍니다.
명령행 인자는 args
배열을 통해서 읽어들일 수 있습니다. 옵션과 마찬가지로 명령행 인자 이름 “name"이 첨자로 사용됩니다.
1
2
3
4
5
6
7
8
9
10
11
12
|
Hello Program
Usage:
hello [options] NAME1 NAME2 ...
Options:
-k, --korean 한국어
-h, --help show this help message and exit
-v, --version show the program version and exit
Arguments:
NAME 이름
|
옵션 다음에 “NAME"인자를 쓸 수 있다고 도움말에 표시됩니다. 인자가 어떤 값인지에 대한 설명은 하단 “Arguments"부분에 출력됩니다.
1
|
php example-3.php bookworm
|
1
|
php example-3.php -k bookworm hellfire
|
1
2
|
안녕하세요. bookworm.
안녕하세요. hellfire.
|
XML#
명령행 인자들에 대한 설정을 PHP 코드가 아닌 XML 파일을 이용해 할 수도 있습니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<command>
<name>hello</name>
<description>Hello Program</description>
<version>1.0.0</version>
<option name="korean">
<short_name>-k</short_name>
<long_name>--korean</long_name>
<description>한국어</description>
<help_name>KOREAN</help_name>
<action>StoreTrue</action>
</option>
<argument name="name">
<description>이름</description>
<multiple>true</multiple>
<help_name>NAME</help_name>
</argument>
</command>
|
fromXmlFile
메소드는 지정한 XML 파일을 읽어들이고 Console_CommandLine
인스턴스를 반환합니다.
1
2
3
4
5
6
7
8
9
10
11
12
|
<?php
require 'vendor/autoload.php';
$parser = Console_CommandLine::fromXmlFile('hello.xml');
try {
$result = $parser->parse();
// ...생략...
} catch (Exception $e) {
$parser->displayError($e->getMessage());
}
|
다음 글에서는 옵션(Option)에 대해 더 자세히 다뤄보려고 합니다.
Console_CommandLine
패키지는 유용한 옵션들을 제공합니다. 이런 옵션들을 적절히 사용하면 깔끔하면서도 강력한 명령행 인자를 사용자에게 제공 할 수 있습니다.
Choices#
1
2
3
4
5
6
7
8
9
|
$parser->addOption(
'color',
[
'short_name' => '-c',
'action' => 'StoreString',
'choices' => ['black', 'white'],
'add_list_option' => true,
]
);
|
Choices는 정해진 값 중 하나만을 인자로 받도록 하는 옵션입니다. 예제처럼 색상을 흰색(white)과 검정색(black)만 받고 싶다면, choices
에 받고자 하는 인자들을 배열로 정의하면 됩니다.
add_list_option
은 기본값이 false
지만, true
로 설정하면 앞에 --list
가 붙은 --list-color
옵션이 자동으로 추가됩니다. 이 옵션을 통해 사용자는 어떤 값들이 선택지로 제공되는지 확인 할 수 있습니다.
Counter#
1
2
3
4
5
6
7
|
$parser->addOption(
'verbose',
[
'short_name' => '-v',
'action' => 'Counter',
]
);
|
Counter 옵션은 사용자가 여러번 중복으로 옵션을 사용했을 경우 사용한 횟수를 값으로 저장합니다. 예를 들어 -v -v -v
와 같이 3번 사용했을 경우 verbose
의 값은 3이 됩니다.
Password#
1
2
3
4
5
6
7
|
$parser->addOption(
'password',
[
'short_name' => '-p',
'action' => 'Password',
]
);
|
Password 옵션은 사용자가 값을 생략했을 경우 프롬프트를 띄우고 직접 입력을 받도록 요청합니다. 이 때 사용자 입력은 화면에 출력되지 않습니다.
Callback#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
function getByteSize($value, $option, $result, $parser, $params = [])
{
static $sizeTable = ['K' => 1024, 'M' => 1048576, 'G' => 1073741824];
// 오류 처리는 생략했습니다.
preg_match('/^(\d+)([KMG])$/i', $value, $matches);
return $matches[1] * $sizeTable[strtoupper($matches[2])];
}
$parser = new Console_CommandLine();
$parser->addOption(
'size',
[
'short_name' => '-s',
'action' => 'Callback',
'callback' => 'getByteSize',
]
);
|
Callback 옵션은 인자 값을 콜백 함수를 통해 전처리하도록 합니다. 예제는 ‘10G’, ‘8M’ 같이 단위를 붙인 크기값을 바이트 단위로 변환하는 코드입니다.
True, False#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
$parser->addOption(
'debug',
[
'short_name' => '-d',
'action' => 'StoreTrue',
]
);
$parser->addOption(
'quiet',
[
'short_name' => '-q',
'default' => true,
'action' => 'StoreFalse',
]
);
|
True, False 옵션은 명령행 인자로 해당 옵션이 주어졌을 때 true
또는 false
값을 저장하도록 합니다. default
를 생략한 경우, 옵션을 사용하지 않으면 null
값이 저장됩니다.
인자, 서브커맨드#
프로그램이 인자(Argument)를 받아들이기 위해서는 addArgument()
메소드를 이용해 인자에 대한 정보를 매개변수로 전달해야 합니다.
1
2
3
4
5
6
7
8
|
$parser->addArgument(
'INPUT',
[
'multiple' => true,
'optional' => true,
]
);
$parser->addArgument('OUTPUT', []);
|
위 코드는 INPUT
과 OUTPUT
인자를 받을 수 있도록 한 것입니다. 여기서 multiple
은 해당 인자가 여러 개 올 수 있다는 것이고, optional
은 생략이 가능하다는 의미입니다. 바꿔말해 INPUT
인자는 생략하거나 여러개를 쓸 수 있고, OUTPUT
은 반드시 하나만 입력해야 한다는 것입니다.
1
2
3
4
5
6
7
8
9
|
Usage:
example-10.php [options] [INPUT1 INPUT2 ...] OUTPUT
Options:
-h, --help show this help message and exit
Arguments:
INPUT
OUTPUT
|
도움말을 통해 이를 다시 확인 해보면 생략 가능하다는 의미로 대괄호로 INPUT
을 감싸고 있고, 여러개 사용이 가능하다는 의미로 뒤에 숫자를 붙인 후 말줄임표를 뒤에 덧붙입니다.
서브커맨드(Subcommand)는 git
처럼 프로그램 실행시 사용 할 수 있는 보조적인 명령어입니다. 예를 들면 git clone ...
같은 명령어에서 clone
부분이 서브커맨드입니다. 서브커맨드가 옵션이나 인자와 다른 점은 서브커맨드 자체적인 옵션과 인자를 가질 수 있다는 것입니다. 바꿔말해 -a
옵션을 그냥 사용했을 때와 서브커맨드 뒤에 붙여서 사용 했을 때 동작이 서로 다르게 할 수 있습니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
$copy = $parser->addCommand('list');
$copy->addOption(
'all',
[
'short_name' => '-a',
'action' => 'StoreTrue',
]
);
$remove = $parser->addCommand('remove');
$remove->addOption(
'recursive',
[
'short_name' => '-r',
'action' => 'StoreTrue'
]
);
$result = $parser->parse();
var_dump($result->command_name);
var_dump($result->command->options);
var_dump($result->command->args);
|
위 코드는 list
와 remove
두개의 서브커맨드를 설정하고 있습니다. list
는 -a
옵션을, remove
는 -r
옵션을 가지고 있습니다.
1
2
|
php ./example-11.php list -a
php ./example-11.php remove -r
|
위처럼 사용하는 것은 가능하지만, php ./example-11.php list -r
은 에러를 냅니다.
어떤 서브커맨드를 사용했는지 확인하기 위해서는 Console_CommandLine_Result
인스턴스의 command_name
프로퍼티 값을 이용하면 됩니다. 또한, 서브커맨드에 사용된 옵션과 인자는 동일한 인스턴스의 command
프로퍼티를 이용합니다. command
는 서브커맨드에 대한 Console_CommandLine_Result
인스턴스입니다.
사용자 정의#
특별한 형식을 가진 옵션을 받는 경우가 종종 있습니다. 예를 들면 IP 같은 것 말입니다. 보통의 경우 IP를 문자열로 받은 후에 문자열이 올바른 IP인지 검사를 합니다만, PEAR Console_CommandLine
에서는 Action을 사용자 정의하여 조금 더 깔끔하고 통일된 형태로 이를 처리 할 수 있습니다.
소스 코드를 설명드리기 전에 첫번째 글에서 보여드렸던 Composer로 PEAR 패키지를 설치하는 방식 대신에 Packagist를 통해 설치하는 것을 보여드리려고 합니다.
1
|
composer require pear/console_commandline
|
위의 명령은 다음과 같은 내용을 가진 composer.json을 생성합니다.
1
2
3
4
5
|
{
"require": {
"pear/console_commandline": "^1.2"
}
}
|
composer를 통해 CommandLine을 설치했으면, 이제 옵션으로 IP를 입력받는 예제 소스 코드를 살펴 보도록 하겠습니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
|
<?php
require 'vendor/autoload.php';
class ActionIP extends Console_CommandLine_Action
{
public function execute($value=false, $params=array())
{
if (ip2long($value) === false) {
throw new Exception('Invalid IP');
}
$this->setResult($value);
}
}
Console_CommandLine::registerAction('StoreIP', 'ActionIP');
$parser = new Console_CommandLine();
$parser->addOption(
'ip',
array(
'short_name' => '-i',
'long_name' => '--ip',
'description' => 'IP Address',
'help_name' => 'IP',
'action' => 'StoreIP'
)
);
try {
$result = $parser->parse();
print_r($result->options);
} catch (Exception $e) {
$parser->displayError($e->getMessage());
};
|
우선 액션을 정의하기 위해서는 Console_CommandLine_Action
클래스를 상속받은 클래스를 하나 정의해야 합니다. 여기서는 일관성을 위해 Action으로 시작하는 ActionIP
클래스를 정의 해 보겠습니다. 이 클래스는 public
인 execute
메소드를 정의해야 합니다. execute
메소드는 옵션의 값을 첫번째 파라미터 $value로 넘겨줍니다. 이 value를 검사하고, 필요하다면 적절히 변형하여 $this->setResult($value)
를 통해 값을 저장하면 내장된 다른 Store 계열 액션들과 마찬가지로 사용 할 수 있게 됩니다.
액션을 처리 할 클래스를 정의했다면 이 클래스를 Consol_CommandLine
에 등록을 시켜주어야 합니다. 이를 처리하는 정적 메소드는 Console_CommandLine::registerAction
으로 첫번째는 옵션을 정의 할 때 쓸 액션의 이름을 받고, 두번째는 액션을 정의한 클래스명을 받습니다.
이렇게 액션을 처리하는 클래스를 정의하고 이를 등록시켜 준 후, 내장된 액션들처럼 자유롭게 사용이 가능해집니다.