php-cs-fixer:フィクサーの作成



コードの品質は、それがどのように機能するかだけでなく、どのように見えるかにもあります。 キャンペーンのフレームワーク内の単一のコードスタイルが非常に重要であるという事実-今日では、誰も納得する必要はありません。 コードは書くだけでなく、設計する必要があります。 PHPコードの設計に関しては、 php-cs-fixerユーティリティが長い間標準になっています。 これを使用するのは非常に簡単で、多くのルールがあり、その起動を嵐のキーの組み合わせまたはgitの事前コミットフックにバインドできます。 これはすべて簡単にグーグルであり、何百もの記事で完全に理解されています。 そして今日は何か他のものについてお話します。 php-cs-fixerには多数の異なるフィクサーがありますが、そこにないフィクサーが必要な場合はどうでしょうか? 独自のフィクサーを書く方法は?



フィクサー



一般に、フィクサーとは何ですか? フィクサーとは、コードをキャプチャして何らかのコードに導く小さなクラスです。 私は新しいフィクサーのばかげたケースや複雑なケースを発明しなかったため、非常に現実的なものを採用することにしました。 たとえば、コード内のすべてのキーワードを小文字にキャストします。 Fixer LowercaseKeywordsFixerこれを担当します 。 彼の例を使用して、独自のフィクサーを作成する方法を学びましょう。



Fixime



あなたはすでに完了しています

git clone https://github.com/FriendsOfPHP/PHP-CS-Fixer.git composer install
      
      





実験フィクサーは2つの部分で構成されています。

フィクサー自体:

src/Fixer/Casing/LowercaseKeywordsFixer.php





そしてテスト:

tests/Fixer/Casing/LowercaseKeywordsFixerTest.php





LowercaseKeywordsFixer.phpは、フィクサークラスを含むファイルです。 各フィクサーは抽象クラスPhpCsFixer \ AbstractFixerから継承する必要があるため、メソッドが含まれます。

 getDefinition(); isCandidate(Tokens $tokens); applyFix(\SplFileInfo $file, Tokens $tokens);
      
      







これらのメソッドに戻ります。 ここで、非常に重要な概念であるトークンを見てみましょう。



PHPトークン



PHPに精通している場合、トークンの概念は新しいものではありません。 ロシア語では、「マーク」と呼ばれることもあります。 トークンはPHP言語のトークンです。 たとえば、このような単純なコードを使用する場合:

 <?php foreach ($a as $B) { try { new $c($a, isset($b)); } catch (\Exception $e) { exit(1); } }
      
      







トークンに分割すると、54個の要素の配列が得られます。 2番目の要素は次のとおりです。



 Array ( [0] => 334 [1] => foreach [2] => 3 )
      
      







ここで、334はトークンIDです。 つまり、この特定のトークンではなく、このタイプのトークンです。 言い換えると、foreach構造を表すすべてのトークンは識別子382を持ちます。この識別子は定数T_FOREACHに対応します。 すべての定数のリストは、ドキュメントに記載れています



非常に重要なポイント。 識別子は、PHPインタープリターのバージョンによって異なります。コードは特定の数字に依存せず、 定数のみに依存する必要があります。



トークンの詳細については、 ドキュメントをご覧ください。



php-cs-fixerのトークン



php-cs-fixerでトークンを操作するための2つのクラスがあります。

PhpCsFixer \ Tokenizer \トークンの配列を操作するためのトークン、および

PhpCsFixer \ Tokenizer \単一のトークンで作業するためのトークン。

いくつかの便利な方法を検討してください。



トークン:
 equals($other, $caseSensitive = true)
      
      





最初のパラメーターで渡されたトークンが現在のトークンと同等であることを確認します。 これは、トークンが等しいことを確認する最も正しい方法です。

 equalsAny(array $others, $caseSensitive = true);
      
      





最初のパラメーターで渡されたトークンの1つが現在のトークンと等しいことを確認します。



 getContent();
      
      





トークンの内容を取得します。



 setContent($content);
      
      





トークンの内容を設定します。



 isChanged();
      
      





トークンがすでに変更されているかどうか。



 isKeyword(); isNativeConstant(); isMagicConstant(); isWhitespace();
      
      





名前はそれ自体を物語っています。

詳細





トークン:
 findBlockEnd($type, $searchIndex, $findEnd = true);
      
      





インデックス$ searchIndexのトークンから開始して、タイプ$タイプ(中、正方形、または括弧)のブロックの終わりを見つけます。 3番目のパラメーターとしてtrueを渡すと、メソッドはブロックの始まりではなく、終わりを探します。



 findGivenKind($possibleKind, $start = 0, $end = null);
      
      





インデックス$ startの下のトークンからインデックス$ endの下のトークンまでの特定のタイプ(配列を渡す場合はタイプ)のトークンを検索します。



 generateCode();
      
      





トークンのセットからPHPコードを生成します。



 generatePartialCode($start, $end);
      
      





$ startから$ endまでのトークンのセットからPHPコードを生成します

 getNextTokenOfKind($index, array $tokens = array(), $caseSensitive = true);
      
      





特定のタイプの次のトークンを見つける



 getNextMeaningfulToken($index); getPrevMeaningfulToken($index);
      
      





スペースとコメント以外の何かを含む次/前のトークンを見つけます。



 insertAt($index, $items);
      
      





$インデックスの後に、コレクションに新しいトークンを追加します

 overrideAt($index, $token);
      
      





トークンをindex $ indexで置き換え、2番目のパラメーターで渡されたトークンに置き換えます。

詳細





フィクサーを書く



次に、フィクサー自体について説明します。

すべてのPHPキーワードを小文字に変換するフィクサーを作成していることを思い出してください。 コミットクラスはファイルにあります

src/Fixer/Casing/LowercaseKeywordsFixer.php





まず、コードがケースに該当するかどうかを判断する必要があります。 この場合、phpキーワードを含むコードを処理する必要があります。 isCandidateメソッドを定義します。



 public function isCandidate(Tokens $tokens) { return $tokens->isAnyTokenKindsFound(Token::getKeywords()); }
      
      





次に、定着液について説明する必要があります。 これを行うには、メソッドを定義します。

 public function getDefinition() { return new FixerDefinition( 'PHP keywords MUST be in lower case.', array( new CodeSample( '<?php FOREACH($a AS $B) { TRY { NEW $C($a, ISSET($B)); WHILE($B) { INCLUDE "test.php"; } } CATCH(\Exception $e) { EXIT(1); } } ' ), ) ); }
      
      







このメソッドはFixerDefinitionオブジェクトを返します。コンストラクターは2つのパラメーターを取ります。フィクサーの簡単な説明( README.rstファイルのドキュメントに記載されます)と修正用の小さなサンプルコード(どこにも表示されませんが、テストに参加します)。



メソッドを実装することもできます

 public function getPriority() { return 0; }
      
      





他の修正の前または後に修正プログラムを実行する必要がある場合、修正プログラムの優先度を返します。 この場合、フィクサーは残りの部分に依存しないため、親クラスの値を0のままにしてメソッドを実装することはできません。



すべての準備が完了しました。コードを修正するメソッドを実装しましょう。

トークンがキーワードである場合、コード全体を実行し、小文字にする必要があります。



 protected function applyFix(\SplFileInfo $file, Tokens $tokens) { foreach ($tokens as $token) { if ($token->isKeyword()) { $token->setContent(strtolower($token->getContent())); } } }
      
      







結果はこのファイルのようなものになるはずです



次は何ですか



修正可能なフィクサーがあります。 これは素晴らしい。 少し残った。 彼のためにテストを書きましょう。 私たちのテストはファイルにあります

tests/Fixer/Casing/LowercaseKeywordsFixerTest.php





これは、独自のメソッドがあることを除いて、通常のPHPUnitテストです。

 doTest($expected, $input = null, \SplFileInfo $file = null)
      
      





期待される結果を最初のパラメーターとして、元のコードを2番目のパラメーターとして受け取ります。 試験方法:



 /** * @param string $expected * @param null|string $input * * @dataProvider provideExamples */ public function testFix($expected, $input = null) { $this->doTest($expected, $input); }
      
      





データプロバイダーを作成しましょう。



 public function provideExamples() { return array( array('<?php $x = (1 and 2);', '<?php $x = (1 AND 2);'), array('<?php foreach(array(1, 2, 3) as $val) {}', '<?php FOREACH(array(1, 2, 3) AS $val) {}'), array('<?php echo "GOOD AS NEW";'), array('<?php echo X::class ?>', '<?php echo X::ClASs ?>'), ); }
      
      





その結果、このようなコードを取得します



テストは機能します。テストのみを実行すると、すべてが成功します。 しかし、一般的なテストは失敗します、なぜなら ドキュメントには、定着液に関するデータはありません。 php-cs-fixerのドキュメントは自動生成されるため、次を実行します。

 php php-cs-fixer readme > README.rst
      
      





そして、フィクサーに関する情報がドキュメントに追加されます。

次に、コードスタイルに準拠しているかどうか、両方のファイルを確認する必要があります。

 php ./php-cs-fixer fix
      
      





最後に、一般的なテストを実行します。

 phpunit ./tests
      
      





すべてがうまくいけば、あなた自身の定着液の準備ができています。 その後、 プルリクエストを行うと、しばらくすると作成がphp-cs-fixerに表示されます。



All Articles