PHP自動補完インタラクティブコンソール

この小さな記事では、PHPスクリプトのTabスクリプトでオートコンプリートを使用してコンソールを使用する方法を示します。 ハブに関する同様の記事の中で、 CKOPOBAPKuHからの記事のみを見つけました。本質は同じですが、方向が少し異なります。



実際、ここには魔法はありません。難点は、コンソールがどのように機能するかを自分で定式化することです。 したがって、最小限の単語、最小限のコード、最も必要なもののみ。



質問があります:PHPでコマンドとヒントを使用して独自のコンソールを作成することは可能ですか(可能であれば、どのように可能ですか)。

答えがあります:可能ですが、PHPの対応する拡張機能(readline)は、残念ながらLinuxでのみ利用可能です。







それでは始めましょう。



アクションプランは次のとおりです。

-Tabキーを押して受信データを処理し、自動補完用のコマンドのリストを返すメソッドを準備しています。

-補完するためにこれらの同じチームのリストを準備します

-無限のプログラムループを整理して終了-コマンド「exit」で



他に何も必要ないように。



それをもう少し面白くするために、コンソールに、今では置換が必要であることを理解させます。 置換の2つの「レベル」を作成します。コンソールで最初の単語を入力するとき、アクションを提供し、2番目の単語を入力するとき-名詞。 コンソールにさらに単語がある場合、Tabキーを押しても行は変更されません。



この例では、関数が必要です。

-readline_completion_function-独自の入力行処理関数を登録します

-readline-行を読む

-readline_info-その助けを借りて、Tabキーを押してコンソールの行に関する詳細情報を確認します。



実際、作業はほとんどないので、すぐに要点を説明します。 語彙とコマンド処理を担当する小さなクラスのコードは次のとおりです。



Dictionary.php
class Dictionary { const EXIT_COMMAND = 'exit'; protected $mainDictionary = [ 'list', 'load', 'get', 'go', 'put', 'parse', 'paint', 'delete', 'download', self::EXIT_COMMAND ]; protected $subDictionary = [ 'level', 'library', 'document', 'dragon', 'daemon', 'data', 'port', 'password', 'paragraph' ]; private $promptLine = '> '; public function initCommandCompletion() { // if readline lib accessible - use it for command completions if (function_exists('readline_completion_function')) { readline_completion_function( function ($currWord, $stringPosition, $cursorInLine) { $fullLine = readline_info()['line_buffer']; if (count( explode(' ', $fullLine) ) > 2 ) { return []; } // if not first word - return list allowed commands if (strrpos($fullLine, ' ') !== false && ( strrpos($fullLine, $currWord) === false || strrpos($fullLine, ' ') < strrpos($fullLine, $currWord)) ) { return $this->subDictionary; } return $this->mainDictionary; } ); } } public function readCommand() { if (function_exists('readline')) { $command = readline($this->promptLine); } else { fputs(STDOUT, $this->promptLine); $command = fgets(STDIN); } return $command; } public function executeCommand($command) { $param = ''; if (strpos($command, ' ') !== false) { list ($command, $param) = explode(' ', $command, 2); } // NEED TO CHECK EXISTS COMMAND if (!$this->isCommandExists($command)) { fputs(STDOUT, "Hey! I don't know what are you talking about!\n"); return false; } // AND NOW CHECK FOR COMMAND AND RUN IT $message = "You try to run command '{$command}'"; if (!empty($param)) { $message .= " and with param '{$param}'."; } fputs(STDOUT, $message . "\n"); return true; } private function isCommandExists($command) { return in_array($command, array_merge($this->mainDictionary, $this->subDictionary)); } }
      
      









私たちの目的にとって、すべての最も必要で興味深いのはinitCommandCompletion()メソッドです。 その他...そして、これ以上面白いものはありません。 呼び出すときに使用する匿名関数は、コンソールからの最後の単語を最初のパラメーターとして受け取ります。完全な行を取得するには、readline_info()を使用する必要があります。 それでは、今-単語が入力されている順序を確認し、自動置換の辞書の1つを返します。



そして効果を得るには、このクラスを使用します。 次の内容でindex.phpを作成します。



index.php
 require_once __DIR__ . '/Dictionary.php'; $app = new Dictionary(); $app->initCommandCompletion(); // START LOOP. 'exit' command will stop execution while (true) { $command = $app->readCommand(); $command = trim($command); if ($command == Dictionary::EXIT_COMMAND) { break; } $app->executeCommand($command); } exit;
      
      









魔法はありません、すべてが非常に簡単です:



最初の単語-1つの辞書が使用されます:

 $ php index.php > l[Tab] list load >l
      
      







2番目の単語については、別の:

 $ php index.php > li[Tab] > list l[Tab] level library >list l
      
      







まあ、それだけです。



拡張機能では、チームの履歴を操作する方法が引き続き利用できるため、ヘリコプターを作成できます。



どのように使用するかはあなた次第です。

実験として、コンソールを理解した後、プレイヤーが周りを回ってオブジェクトを拾ったり、インベントリから捨てたりできるように、いくつかの部屋とオブジェクトを含むテキストゲームのスケッチを作成しました。 したがって、コマンドのセット、およびコマンドの2番目の単語については、部屋とインベントリ内のアイテムの名前が表示されます。



のこぎりは面白かった。 熱意の第一波、いわば。 :)



情報源、 ここで突然誰かが好奇心が強い場合。



PSそのようなもっと深刻なことをするつもりなら、Symfony2のコンソールコンポーネントを見てください。 すべてが正しく行われているので、自転車を無駄にする必要はありません。



All Articles