【PHP8.x】getopt関数の使い方

作成日: 更新日:

『getopt関数は、コマンドラインからスクリプトに渡された引数を解析するために使用する関数です。PHPスクリプトをコマンドラインで実行する際に、ユーザーが指定したオプション(例: -v--file=test.txt)を簡単に扱えるようになります。この関数は、指定されたルールに基づいて引数を解析し、結果を連想配列として返します。第一引数には、認識させたい短いオプション(ハイフン1つで始まる)の文字列を指定します。例えば、「a」は値を取らないオプション、「b:」は必須の値を伴うオプション、「c::」は任意の値を伴うオプションとして定義します。第二引数には、長いオプション(ハイフン2つで始まる)を配列で指定します。こちらも短いオプションと同様に、オプション名の後にコロンを付けることで値の要否を制御できます。第三引数に変数を渡すと、オプションの解析が終了した位置のインデックスがその変数に格納されます。これにより、オプションではない通常の引数を区別できます。解析に成功するとオプション名と値のペアからなる連想配列が返され、失敗した場合はfalseが返ります。この関数を使うことで、柔軟なコマンドラインツールをPHPで効率的に作成できます。』

基本的な使い方

構文(syntax)

<?php
$shortopts  = "ab:c::";
$longopts   = [
    "option1",
    "option2:",
    "option3::",
];

$options = getopt($shortopts, $longopts);
?>

引数(parameters)

string $short_options, array $long_options = [], ?int &$rest_index = null

  • string $short_options: 短縮オプションの指定。例: "a::b"
  • array $long_options = []: 長縮オプションの指定。連想配列でキーにオプション名、値に引数の有無を指定。例: ["opt1" => \PHP_GETOPT_OPTIONAL_ARGUMENT, "opt2" => \PHP_GETOPT_REQUIRED_ARGUMENT]
  • ?int &$rest_index = null: オプションとして解析されなかった引数の配列のインデックスを格納する変数への参照。NULL許容。

戻り値(return)

array|false

getopt関数は、コマンドライン引数を解析し、その結果を連想配列として返します。解析に失敗した場合はfalseを返します。

サンプルコード

PHP getoptでコマンドライン引数を解析する

<?php

/**
 * コマンドラインから渡された引数を getopt() を使って解析するサンプルスクリプト。
 *
 * このスクリプトは、ファイルパスを指定するオプション (-f or --file) と、
 * 冗長な出力を有効にするオプション (-v or --verbose) を受け取ります。
 * オプション以外の引数もリストアップします。
 *
 * [実行方法]
 * ターミナルで以下のコマンドを実行してみてください。
 *
 * 1. 短いオプションと長いオプションを両方使う:
 *    php a.php -f /path/to/input.txt --verbose item1 item2
 *
 * 2. 長いオプションのみ使う (引数は = で渡すことも可能):
 *    php a.php --file=/path/to/output.log item3
 *
 * 3. 引数を取らないオプションのみ使う:
 *    php a.php -v item4
 *
 * 4. オプションを使わない:
 *    php a.php item5 item6
 */

// 短いオプションの定義
// "f:" : -f オプションが必須の引数を取ることを示す (例: -f filename.txt)
// "v"  : -v オプションが引数を取らないことを示す (フラグとして機能)
$short_options = "f:v";

// 長いオプションの定義
// "file:"   : --file オプションが必須の引数を取ることを示す (例: --file=filename.txt)
// "verbose" : --verbose オプションが引数を取らないことを示す
$long_options = [
    "file:",
    "verbose",
];

// getopt() を使ってコマンドライン引数を解析する
// 3番目の引数 $rest_index には、オプションとして解釈されなかった
// 最初の引数のインデックスが格納される (PHP 8.0.0 以降)
$options = getopt($short_options, $long_options, $rest_index);

// --- 解析結果の表示 ---

// --file または -f オプションが指定されたかチェック
if (isset($options['file']) || isset($options['f'])) {
    // 短いオプションと長いオプションは同時に指定できないため、?? (Null合体演算子) で値を取得
    $filePath = $options['file'] ?? $options['f'];
    echo "ファイルパスが指定されました: " . $filePath . PHP_EOL;
}

// --verbose または -v オプションが指定されたかチェック
if (isset($options['verbose']) || isset($options['v'])) {
    echo "冗長モードが有効です。" . PHP_EOL;
}

// オプション以外の引数を表示する
// $argv と $argc はPHPが自動的に定義するグローバル変数
// $argc: コマンドライン引数の数
// $argv: コマンドライン引数の配列
echo "---" . PHP_EOL;
echo "オプション以外の引数リスト:" . PHP_EOL;
for ($i = $rest_index; $i < $argc; $i++) {
    echo $argv[$i] . PHP_EOL;
}

if ($argc <= 1) {
    echo "オプションや引数が指定されていません。上記の実行方法を参考にしてください。" . PHP_EOL;
}

?>

PHPのgetopt関数は、コマンドラインからスクリプトに渡された引数を解析するために使用されます。バージョン8以降のPHPで利用可能です。

この関数は、プログラム実行時に指定されるオプションを定義し、その値を取得します。

最初の引数$short_optionsには、短いオプション(1文字のオプション、例: -f)を文字列で指定します。「:`」(コロン)をオプション名の後ろに付けると、そのオプションが必須の引数を取ることを示します。

二番目の引数$long_optionsには、長いオプション(複数文字のオプション、例: --file)を配列で指定します。同様に、「:`」をオプション名の後ろに付けると、必須の引数を取ることを示します。

三番目の引数$rest_indexは参照渡しで、PHP 8.0.0以降では、オプションとして解析されなかった最初の引数のインデックスが格納されます。これにより、オプション以外の残りの引数を取得できます。

getopt関数は、解析されたオプションとその値を含む連想配列を返します。もし解析に失敗した場合はfalseを返します。

サンプルコードでは、-fまたは--file(ファイルパス指定)と、-vまたは--verbose(冗長モード)のオプションを定義し、その値を解析しています。解析結果の$options配列から値を取得し、$rest_index$argvを使ってオプション以外の引数を表示することで、コマンドラインからの入力に柔軟に対応しています。

getopt関数では、オプション定義にコロン(:)を付けるかで、そのオプションが引数を取るかフラグとして機能するかが決まる点にご注意ください。短いオプションと長いオプションで同じ機能を持つ場合、戻り値の配列では両方のキーが存在する可能性があるので、??演算子を用いて安全に値を取得してください。オプション以外の引数は、getoptの第三引数$rest_indexとグローバル変数$argvを組み合わせて取得します。また、getoptは解析に失敗するとfalseを返すため、戻り値がarrayfalseかを常に確認し、適切なエラーハンドリングを行うことが重要です。

PHP getopt でコマンドライン引数をパースする

<?php

/**
 * コマンドライン引数をパースし、その結果を表示するサンプルコードです。
 * getopt関数がPHP 8でどのように動作し、異なる形式のオプションをどのように扱うかを示します。
 * 「php getopt not working」という問題に直面した場合、引数の定義と渡し方が
 * このサンプルと一致しているか確認することで、原因を特定しやすくなります。
 *
 * このコードを実行するには、PHP CLIを使用します。
 *
 * 実行例:
 * 1. オプションなしの場合:
 *    php your_script_name.php
 *
 * 2. 短いフラグオプションと、短い値必須オプションの場合:
 *    php your_script_name.php -a -b valueB
 *
 * 3. 長いフラグオプションと、長い値必須オプションの場合:
 *    php your_script_name.php --verbose --file=path/to/my/document.txt
 *
 * 4. 値が任意のオプションの場合:
 *    php your_script_name.php -n OptionalValue --name="John Doe"
 *    php your_script_name.php -n --name
 *
 * 5. ヘルプオプションの場合:
 *    php your_script_name.php --help
 *
 * 6. 必須オプションの値が指定されなかった場合 (この場合、そのオプションの値はnullになります):
 *    php your_script_name.php -b --file
 *
 * 7. 同じオプションを複数回指定した場合 (値は配列として格納されます):
 *    php your_script_name.php --name=Alice --name=Bob -b val1 -b val2
 */
function parseCommandLineOptions(): void
{
    // 短いオプションの定義:
    //   'a'  : 値なし (フラグオプション)
    //   'b:' : 値が必須
    //   'n::': 値が任意 (オプションの値)
    $shortOptions = "ab:n::";

    // 長いオプションの定義:
    //   "verbose"  : 値なし (フラグオプション)
    //   "file:"    : 値が必須
    //   "name::"   : 値が任意 (オプションの値)
    //   "help"     : 値なし (フラグオプション)
    $longOptions = [
        "verbose",
        "file:",
        "name::",
        "help"
    ];

    // getopt関数でコマンドライン引数をパースします。
    // パースエラーが発生した場合、getoptはfalseを返します。
    // オプションが一つも指定されなかった場合は、空の配列を返します。
    $options = getopt($shortOptions, $longOptions);

    if ($options === false) {
        echo "エラー: コマンドライン引数のパースに失敗しました。\n";
        echo "定義されていないオプションや不正な形式が指定されている可能性があります。\n";
        return;
    }

    echo "--- パースされたオプション ---\n";

    if (empty($options)) {
        echo "オプションは指定されていません。\n";
    } else {
        foreach ($options as $opt => $val) {
            if (is_array($val)) {
                // 同じオプションが複数回指定された場合
                echo "オプション '{$opt}': [" . implode(", ", $val) . "]\n";
            } elseif ($val === true) {
                // 値なしのフラグオプション (例: -a, --verbose)。PHP 8の挙動。
                echo "オプション '{$opt}': (フラグ)\n";
            } elseif ($val === null) {
                // 値が必須のオプションだが、値が提供されなかった場合。
                // (例: `-b` が定義されているが `-b` の後に値がない)
                echo "オプション '{$opt}': (値なし - 必須オプションの値が指定されなかった可能性)\n";
            } else {
                // 値ありのオプション (例: -b valueB, --file=path/to/file)。
                echo "オプション '{$opt}': '{$val}'\n";
            }
        }
    }
    echo "--------------------------\n";

    // `--help` オプションが指定された場合の特別な処理
    if (isset($options['help'])) {
        echo "\nこのスクリプトは、コマンドライン引数を処理する方法を示します。\n";
        echo "利用可能なオプション:\n";
        echo "  -a                  : 短いフラグオプション (例: -a)\n";
        echo "  -b <value>          : 短い、値必須オプション (例: -b my_value)\n";
        echo "  -n [<value>]        : 短い、値任意オプション (例: -n or -n some_value)\n";
        echo "  --verbose           : 長いフラグオプション (例: --verbose)\n";
        echo "  --file=<value>      : 長い、値必須オプション (例: --file=path/to/data.txt)\n";
        echo "  --name[=<value>]    : 長い、値任意オプション (例: --name or --name=Alice)\n";
        echo "  --help              : このヘルプメッセージを表示します。\n";
    }
}

// スクリプトがPHP CLI環境で直接実行された場合にのみ関数を呼び出す
if (php_sapi_name() === 'cli') {
    parseCommandLineOptions();
}

PHP 8のgetopt関数は、コマンドラインインターフェース(CLI)でPHPスクリプトを実行する際に、ユーザーが指定したオプション(引数)を効率的に解析するために使用されます。この関数は、-aのような短いオプションと--verboseのような長いオプションの両方を柔軟に扱います。

第一引数$short_optionsでは、短いオプションの定義を文字列で行います。オプション名の後にコロン:を付けると値が必須、二重コロン::を付けると値が任意となります。第二引数$long_optionsは、長いオプションの定義を配列で行い、同様にコロンで値の要件を指定します。

getopt関数は、パースに成功した場合、オプション名とパースされた値を関連付けた連想配列を返します。値を持たないフラグオプション(例: -a)はtrueとして扱われ、値が必須なオプションで値が指定されなかった場合はnullとなります。同じオプションが複数回指定された場合は、値が配列として格納されます。引数の定義が不正であったり、未定義のオプションが指定されたりしてパースに失敗した場合はfalseを返します。

getoptが期待通りに動作しないと感じる場合、「php getopt not working」というキーワードで検索されることがありますが、その多くはオプションの定義とコマンドラインでの指定方法が正確に一致しているかを確認することで解決できます。

getopt関数では、短いオプションや長いオプションの定義において、値の有無や任意性を表す記号(:::)が重要です。これらが正しく定義されていないと、期待通りにコマンドライン引数をパースできません。パース処理に失敗した場合、getoptfalseを返すため、必ず戻り値をチェックし、エラー処理を適切に行うべきです。

PHP 8以降では、値を持たないフラグオプション(例: -a, --verbose)はtrueとして扱われます。一方で、値が必須と定義されているオプションに値が指定されなかった場合(例: -bのみで値なし)、その値はnullとなります。これらの違いを理解し、戻り値の型に応じた適切な処理を行うことが安全なコード利用に繋がります。また、同じオプションが複数回指定されると、値は配列として格納されますので、この点も考慮してください。本関数はPHP CLI環境での実行を想定しています。

【PHP8.x】getopt関数の使い方 | いっしー@Webエンジニア