PHPでCLIツールを書いてみる
はじめに
誰得だが、あまりPHPでCLIツールを書く記事が見つからなかったので書いてみました。本記事では、以下の3種類のCLIツールを書いてみます。
- コマンドライン引数で受け取ったファイルの中身を出力(catコマンドもどき)
- コマンドライン引数で受け取ったURLにアクセスしてリソースをダウンロード(curlコマンドもどき)
- コマンドライン引数で受け取ったPHPファイルの抽象構文木(AST)を出力
例: catコマンド
あーだこーだいうより、コードを見せた方が早いでしょう。
#!/usr/bin/env php <?php function dump($filename) { $handle = fopen($filename, "r") or die("ファイルのオープンに失敗しました"); while (($buffer = fgets($handle, 4096)) !== false) { echo $buffer; } fclose($handle); } $argv = array_slice($argv, 1); if (count($argv) < 1) { print "ファイル名を指定してください\n"; exit(1); } foreach ($argv as $filename) { dump($filename); }
特に引っかかったところはないです。ポイントを強いて挙げるとするなら、インタプリタの絶対パスを指定せず、/usr/bin/env
を使ってインタプリタを$PATH
から検索しているところでしょうか。
実行してみます。
$ ./cat ./hello.php ./cat <?php echo "Hello\n"; #!/usr/bin/env php <?php function dump($filename) { $handle = fopen($filename, "r") or die("ファイルのオープンに失敗しました"); while (($buffer = fgets($handle, 4096)) !== false) { echo $buffer; } fclose($handle); } $argv = array_slice($argv, 1); if (count($argv) < 1) { print "ファイル名を指定してください\n"; exit(1); } foreach ($argv as $filename) { dump($filename); }
普通にCLIツールが書けるんですね。普段はphp-fpm
やらmod_php
でしかPHPのインタプリタにアクセスしないので、少し新鮮味を感じました。
例: curlコマンド
#!/usr/bin/env php <?php function curl($url) { $ch = curl_init($url); curl_setopt($ch, CURLOPT_FILE, STDOUT); curl_setopt($ch, CURLOPT_HEADER, 0); curl_exec($ch); if(curl_error($ch)) { fwrite($fp, curl_error($ch)); } curl_close($ch); } $argv = array_slice($argv, 1); if (count($argv) != 1) { print "URLを指定してください\n"; exit(1); } curl($argv[0]);
PHPの標準ライブラリで用意されているlibcurlのラッパーを使いました。使い方はここに書いてます。
実行してみます。
$ ./curl http://example.com <!doctype html> <html> <head> <title>Example Domain</title> <meta charset="utf-8" /> <meta http-equiv="Content-type" content="text/html; charset=utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1" /> <style type="text/css"> body { background-color: #f0f0f2; margin: 0; padding: 0; font-family: -apple-system, system-ui, BlinkMacSystemFont, "Segoe UI", "Open Sans", "Helvetica Neue", Helvetica, Arial, sans-serif; } ...
PHPの標準ライブラリを見てみると、割と充実していて(libSVMのラッパーもある)、リッチなCLIツールがかけそうだなという印象を受けました。
例: dump-astコマンド
このコマンドはphp-ast
が必要です。実際に試してみたい方は、ここやここを参考にphp-ast
をインストールしてください。
#!/usr/bin/env php <?php function dumpAst($filename) { $handle = fopen($filename, "r") or die("ファイルのオープンに失敗しました"); $code = ""; while (($buffer = fgets($handle, 4096)) !== false) { $code = $code . $buffer; } fclose($handle); var_dump(ast\parse_code($code, $version=70)); } $argv = array_slice($argv, 1); if (count($argv) != 1) { print "ファイル名を指定してください\n"; exit(1); } dumpAst($argv[0]);
実行してみます。
$ cat hello.php <?php echo "Hello\n"; $ ./dump-ast ./hello.php object(ast\Node)#1 (4) { ["kind"]=> int(132) ["flags"]=> int(0) ["lineno"]=> int(1) ["children"]=> array(1) { [0]=> object(ast\Node)#2 (4) { ["kind"]=> int(282) ["flags"]=> int(0) ["lineno"]=> int(3) ["children"]=> array(1) { ["expr"]=> string(6) "Hello " } } } }
こんな感じで、静的解析ツールも作れそうです。何かの機会に、PHPのソースコードを静的解析して遊んでみる記事でも書こうと思います。(PHPStan
やPhan
などの静的解析ツールがすでにあるので、自分で静的解析ツールを書くメリットがあまりないような気もしますが…)
おわりに
手続き的すぎる…
自分が知っているPHPのCLIツールにartisan
やlaravel
コマンドがあるので、次は、それらのコマンドを参考にして、よりよいCLIツールの書き方を探っていきたいです。