https://a.storyblok.com/f/270183/1368x665/a914c53d00/26mar_dev-blog_read-php-code.jpg

PHPコードが読めなければLLMも読めない

最終更新日 April 2, 2026

所要時間:1 分

AIをめぐっては、多くの誤解や意見、インフルエンサーの宣伝文句がある。誰もが「あなたはAIに対応していますか?

AIがすべてをやってくれるわけではない。AIは AIはしかし、あなたが使っているスタックによっては、その結果はおそらくまちまちだろう。AIを扱う最も重要な方法は、あなたの武器庫にあるツールの追加セットとして扱うことだ。これは結果的に、静的解析、コード・リンター、よく書かれたテストなど、まともなツール一式を持つことの繰り返しでしかない。

AIを使うためのコードベースを準備するために、ここでは PHPのReadalizerというのも、AIツールは、それが読んでいるコードと同じくらい良いものでしかないからだ。

Readalizerとは?

ReadalizerはPHPライブラリで、コードベースに適用される一連のルールからなるAPIを開発者に提供します。実行時に、設定で定義された各PHPファイルを取り込んで トークン化を使用してコードをトークン化します。 抽象構文木.ルールの例は次のようになります。 NoTodoWithoutTicketRule.実行時に、あなたのコードは:

public function(stdObj $myExample) {
	// TODO add some logic
	return stdObject->valid === true; 
}

これは失敗します。ルールでは インラインコメント内にをインラインコメント内で提供しなければならない。ですから、これを修正するには、コメントを修正する必要があります:

public function(stdObj $myExample) {
	// TODO add some logic (DEVEX-2541)
	return stdObject->valid === true; 
}

そこには たくさんあるので ルールがたくさんあるので、そのすべてを説明することはできない。しかし、私たちがすることは、実装と、それがライブのコードベースで重要である理由を示すことだ。

静的解析との違いは?

そう言っていただけるとうれしいです。というのも、基本的に、ルールのセットと合否判定ツールは、以下のような静的アナライザーに似ているからだ。 PHPStanPsalmPHPのような静的解析ツールに似ているからです (どちらも AST を使って PHP コードをトークンに解析します)。しかし、この2つには明確な違いがあります。静的解析はコードの動作を保証します。 Readalizer はコードが動くかどうかを気にしません、 ただ、あなたが与えたルールセットに従っているかどうかだけです。したがって、静的アナライザーはコード品質ツールチェーンの一部であると結論づけることができますが、Readalizerの最大の使用例は、人間と大規模言語モデルの両方があなたのコードを読み、あなたが実装したルールセットによって改善された判断を下せるようにすることです。

著者自身の言葉によるリーダライザー

私が今記事でとても好きなのは、プロジェクトのクリエーターに、そのプロジェクトの成り立ちとプロジェクトの目標を尋ねることだ。 という質問だ。そこで、Readalizerとは何なのかについて、以下のように語ってくれた。 クリストファー・ミラーの言葉を紹介しよう:

"Readalizerは、PHPコードを理解するために、あなたとAIエージェントの両方をサポートするためにゼロから設計されました。このパッケージを始めるきっかけとなったのは、Ondrej Mirtes氏の「PHPStanは、あなたのコードがどのように見えるかには関心がない。それは他人の仕事だ。私のキャリアのほとんどを、読みやすいコードについて話すことに費やしてきたので、そろそろ何かしてもいい頃だと思った。そこでReadalizerの登場だ。設定、カスタム・ルール、カスタム・ルールセットを使ってルールをカスタマイズすることができる。"

Vonage PHP SDKでReadalizerを実行する

これが実際にどのように機能するかを見るために、Readalizerを実際のコードベースに対して実行してみよう。 Vonage PHP SDK.

ここでのゴールは単純で、コードの一貫性を向上させることで、人間にとってもLLMにとってもプロジェクトを理解しやすくなる箇所を特定することだ。

始めるには2つのステップを踏むだけだ:

composer require readalizer/readalizer

vendor/bin/readalizer --init

これで readalizer.phpコンフィグをプロジェクトのルートに追加します。素晴らしい。ディレクトリを探すようにボイラープレートを修正した。 srcディレクトリをデフォルトで探すようにボイラープレートを修正し、すべてのルールを一時的に無効にした。

<?php

declare(strict_types=1);

use Readalizer\Readalizer\Rules\ClassNamePascalCaseRule;

use Readalizer\Readalizer\Rules\NoStaticPropertyRule;

use Readalizer\Readalizer\Rules\RequireNamespaceRule;

use Readalizer\Readalizer\Rules\StrictTypesDeclarationRule;

use Readalizer\Readalizer\Rules\PropertyNameCamelCaseRule;

use Readalizer\Readalizer\Rules\ConstantUpperCaseRule;

use Readalizer\Readalizer\Rules\ExceptionSuffixRule;

/**

* Copy this to readalizer.php in your project root and configure your rules.

*

* Each rule is a class implementing RuleInterface (node-level) or

* FileRuleInterface (file-level). Rules can live anywhere.

*

* ── Suppressing violations ───────────────────────────────────────────────────

*

* PHP attribute on a class, method, property, or parameter:

*

*   use Readalizer\Readalizer\Attributes\Suppress;

*

*   #[Suppress]                                   // suppress ALL rules

*   #[Suppress(NoLongMethodsRule::class)]          // suppress one rule

*   #[Suppress(RuleA::class, RuleB::class)]        // suppress multiple

*

* Scope: a class-level attribute suppresses everything within the class;

* a method-level attribute suppresses everything within that method.

*

* Inline comment for line-level suppression (trailing or preceding line):

*

*   $x = something(); // @readalizer-suppress NoLongMethodsRule

*   // @readalizer-suppress                   (preceding line, suppress all)

*   // @readalizer-suppress RuleA, RuleB      (preceding line, suppress named)

*/

return [

   // Paths to scan when no paths are passed on the CLI.

   'paths' => [

       'src',

   ],

   // Memory limit for analysis (default: 2G).

   'memory_limit' => '2G',

   // Cache results between runs.

   'cache' => [

       'enabled' => true,

       'path' => '.readalizer-cache.json',

   ],

   // Optional baseline file to suppress known violations.

   // 'baseline' => '.readalizer-baseline.json',

   // Paths, directory prefixes, or glob patterns to exclude from scanning.

   'ignore' => [

       // 'rector.php',

       // 'src/',

       // '*.generated.php',

   ],

   // Choose one or more rulesets (packs).

   'ruleset' => [

       // new FileStructureRuleset(),

       // new TypeSafetyRuleset(),

       // new ClassDesignRuleset(),

       // new MethodDesignRuleset(),

       // new NamingRuleset(),

       // new ExpressionRuleset(),

   ],

   // Add or override rules on top of rulesets.

   'rules' => [

       // File structure

       // new LineLengthRule(maxLeng)th: 120),

       // new CustomFileRule(),

       // Type safety

       // new CustomTypeRule(),

       // Class design

       // new CustomClassRule(),

       // Method design

       // new CustomMethodRule(),

       // Naming conventions

       // new CustomNamingRule(),

       // Expressions & control flow

       // new CustomExpressionRule(),
   ],
];

.次に、ルールをひとつずつ追加していった。まず最初に ClassNamePascalCaseRule()これは、ソースコードのすべてのクラスがPascalCaseであることを確認するものだ(だから、WordPressの開発者は目をそらしたほうがいいかもしれない)。Readalizerを実行し、結果を得た:

[##############################] 100% (319/319) 1s

[OK] No readability violations found.

Time: 1.06s

違反なし.よくやった、 SDK作者!他のを選んだ方が良さそうだ。ということで ExceptionSuffixRule().このルールは /例外's はすべて クラス名にをクラス名に持つことで識別できなければならない。LLMにとって、ファイル構造と命名規則がLLMに予測可能性を与えるからだ。 予測可能性を与えるからだ。 では、これを実行するとどうなるのか?

[##############################] 100% (319/319) 1s

src/Client/Exception/Conflict.php

  line [ExceptionSuffixRule]  Exception class "Conflict" should end with "Exception".

src/Client/Exception/Credentials.php

  line [ExceptionSuffixRule]  Exception class "Credentials" should end with "Exception".

src/Client/Exception/NotFound.php

  line [ExceptionSuffixRule]  Exception class "NotFound" should end with "Exception".

src/Client/Exception/Request.php

  line 10  [ExceptionSuffixRule]  Exception class "Request" should end with "Exception".

src/Client/Exception/Server.php

  line 10  [ExceptionSuffixRule]  Exception class "Server" should end with "Exception".

src/Client/Exception/Transport.php

  line [ExceptionSuffixRule]  Exception class "Transport" should end with "Exception".

[FAIL] Found 6 violations.

Time: 1.10s

嗚呼、これで何かが見えてきた。このように例外を記述するのは悪い判断ではありません。結局のところ、例外は名前空間構造の中でExceptionとして定義されているのですから。しかし、繰り返しになるが、LLMが次の判断を下すためにする作業をできるだけ少なくしたいのだ。もう一度言う、 予測可能性 ここでも、コードベースの予測可能性が鍵となる。

たった6つの違反と、6つのクラス名の変更という修正だけで、これはかなり些細なことのように思える クロードが修正するのは簡単なことのように思える。そこで カーソルでプロンプトを開き、違反箇所を貼り付けて、リファクタリングするように指示する。コードをプッシュしてPRを作成すると、あら不思議:

https://github.com/Vonage/vonage-php-sdk-core/pull/553

それは 一見些細な例のように思えますが、正気かどうかを確認するために、次のように尋ねました。 Gleanに、エージェント体験をより良いものにするためにSDKにどのような改良を加えることができるか、自分の言葉で教えてくれるように頼んでみました。その出力は、私が想定していたことを裏付けてくれました:

  • 構造化推論フィールドの追加APIレスポンスに構造化推論フィールドを追加する

  • 一貫した命名規則を使用する- LLMは意思決定に予測可能性を必要とする

  • 解決アクションを含めるエージェントが問題を解決する方法を知るために、エラー応答に解決アクションを含める

// Example: Exception naming for predictability

// BAD - LLM can't predict this is an exception

class Invalid {}

// GOOD - Clear suffix helps LLM identify exceptions

class InvalidRequestException {}

これで、エージェント自身から1文のプロンプトが出たことになる。

結論

ここでの単純な例は、AIに対応する方法について非常に穏やかなアウトラインを与える役割を果たすが、エージェント体験が多面的なアプローチであることも言及する価値がある。AIで成功するためには、例えばLinkedInのフィードで「Xは悪い、Yを使え」と述べる多くのインフルエンサーの意見には耳を傾けない。それは単純すぎる。Vonageのアプローチは、クロスプラットフォームの取り組みという点で、他の業界リーダーとよく似ている:

  • この記事では、LLMとして動作するエージェントのSDKを改善するためのツールについて説明しました。 OpenClaw

  • その上で、エージェントは代替オプションとしてMCPサーバーを使用するオプションを持つことができるはずです。 は独自のをリリースしています):

  • リファクタリングされ、強化されたコマンドラインインターフェイス(CLI、 Vonageには以前からありました。)のコードベースと一般向けのコマンド構造で、エージェントはCLIを単独で実行することができます。

3つのアプローチで、AIツールに与えられたタスクを達成する最善の方法を決定させる。これがAIに対応する方法だ。

ご質問がある場合、またはあなたが作っているものを共有したい場合は、こちらをクリックしてください。

最新の開発者向けニュース、ヒント、イベント情報をお届けします。

シェア:

https://a.storyblok.com/f/270183/400x385/12b3020c69/james-seconde.png
James SecondeシニアPHPデベロッパー

スタンダップ・コメディーの学位論文を持つ俳優の訓練を受け、ミートアップ・シーンを経てPHP開発に携わるようになった。技術について話したり書いたり、レコード・コレクションから変わったレコードを再生したり買ったりしています。