phpstan-fixer について
PHPStanの静的解析エラーを、型注釈やPHPDoc、コードの改善で修正するためのエージェント向けスキルです。根本原因への対処、プロジェクト設定の尊重、第三者コードを変更しない方針を重視します。
主な機能
- 01PHPStanエラーの文脈分析
- 02型とPHPDocの修正
- 03設定済みの厳格度の尊重
- 04未承認のエラー抑制を回避
- 05スタブによる第三者型の補正
- 06PHPStanで変更を検証
活用シーン
- 01不足している型宣言の補完
- 02引数と戻り値の型の修正
- 03フレームワーク固有の型問題への対応
- 04vendorライブラリの型エラーへの対処
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ marcelorodrigo/ agent-skills --skill phpstan-fixerインストール後、Claude Code で/phpstan-fixerを入力して読み込まれたか確認します。
詳細
PHPStan エラー修正ツール
適切な型注釈、PHPDoc、コードの改善を通じて、PHPStan の静的解析エラーを修正します。このスキルでは、プロジェクトに設定された厳格さのレベルを尊重しながら、エラーを抑制せずに解決する方法をエージェントに教えます。
基本原則
- 最初の手段としてエラーを抑制しない — 適切な型と注釈を使って根本原因を修正します
- ユーザーの設定を尊重する —
phpstan.neonの設定(レベル、パス、パラメーター)は変更しません - 黙って無視しない — ユーザーの明示的な承認なしに、設定に
ignoreErrorsを追加しません - コンテキストを考慮して修正する — 解決策を提案する前に、プロジェクトの種類(Laravel、Symfony、素の PHP)を把握します
- 無視する前に確認する — 正当な理由でエラーを無視する必要がある場合は、その理由を説明し、先にユーザーの承認を得ます
- サードパーティーのコードは修正しない —
vendor/内のファイルは変更しません。誤った型を上書きするにはスタブファイルを使用します
ワークフロー
ステップ 1:プロジェクトのコンテキストを把握する
エラーを修正する前に、プロジェクトの種類を特定します。
# Check for Laravel
grep laravel/framework composer.json
# Check for Symfony
grep symfony/symfony composer.json
# Check for PHPStan extensions
grep phpstan composer.json
# Read PHPStan config
cat phpstan.neon
# Check project guidelines
cat AGENTS.md
抽出する主な情報:
- PHPStan のレベル(0~10、または max)
- インストール済みの PHPStan 拡張機能(larastan、phpstan-strict-rules など)
- フレームワーク固有のヘルパー(Laravel IDE Helper、Symfony プラグイン)
- プロジェクト固有の型に関する規約
ステップ 2:エラーを分析する
PHPStan のエラーは次の構成になっています。
------ ----------------------------------------------
Line /path/to/File.php
------ ----------------------------------------------
42 Parameter $user of method foo() has invalid
type App\User.
💡 Identifier: parameter.type
------ ----------------------------------------------
抽出する情報:
- エラー識別子(例:
parameter.type、missingType.return) - エラーの場所(ファイル、行番号)
- コンテキスト(このコードは何をしようとしていますか?)
ステップ 3:適切な修正を適用する
エラー識別子を使って、修正方法を判断します。
ステップ 4:修正を検証する
修正を適用した後、PHPStan を再度実行して確認します。
vendor/bin/phpstan analyse
重要:
- 新しいエラーが発生した場合、修正が誤っていた可能性があります。エラーを再分析し、別の方法を試してください。
- 同じエラーが残る場合、修正は正しく適用されていません。コードを再確認してください。
- エラーが解消された場合は、修正が成功したことを記録し、次のエラーに進んでください。
よくあるエラーの修正
型関連のエラー
missingType.parameter — パラメーターの型がありません
エラー:
Parameter $name has no type specified.
修正 — ネイティブ型を追加:
// Before
function greet($name) {
return "Hello, $name";
}
// After
function greet(string $name): string {
return "Hello, $name";
}
修正 — 複雑な型には PHPDoc を使用:
// Before
function processUsers($users) { ... }
// After
/**
* @param array<int, User> $users
*/
function processUsers(array $users): void { ... }
missingType.return — 戻り値の型がありません
エラー:
Method foo() has no return type specified.
修正 — ネイティブの戻り値の型を追加:
// Before
public function getUser() {
return $this->user;
}
// After
public function getUser(): User {
return $this->user;
}
修正 — 共用型/交差型には PHPDoc を使用:
// Before
public function findUser($id) { ... }
// After
/**
* @return User|null
*/
public function findUser(int $id): ?User { ... }
argument.type — 引数の型が誤っています
エラー:
Parameter #1 $id of method find() expects int, string given.
修正 — 引数をキャスト:
// Before
$user = $repository->find($request->input('id'));
// After
$user = $repository->find((int) $request->input('id'));
修正 — 早い段階で型を絞り込み:
// Better approach
$id = $request->integer('id'); // Laravel helper
$user = $repository->find($id);
return.type — 戻り値の型が誤っています
エラー:
Method foo() should return User but returns User|null.
修正 — 戻り値の型を調整:
// Before
public function getUser(): User {
return $this->user ?? null;
}
// After
public function getUser(): ?User {
return $this->user ?? null;
}
修正 — アサーションで null 以外であることを保証:
public function getUser(): User {
assert($this->user !== null);
return $this->user;
}
プロパティのエラー
property.notFound — 未定義のプロパティへのアクセス
エラー:
Access to an undefined property User::$name.
修正 — プロパティ宣言を追加:
class User {
private string $name;
public function __construct(string $name) {
$this->name = $name;
}
}
修正 — マジックプロパティをドキュメントに記載:
/**
* @property string $name
*/
class User {
public function __get($key) { ... }
}
修正(Laravel)— IDE Helper を使用:
# Generate PHPDocs for Eloquent models
php artisan ide-helper:models
property.onlyWritten — プロパティに書き込みはあるが、読み取りがない
エラー:
Property User::$name is never read, only written.
修正 — 未使用のプロパティを削除するか、ゲッターを追加:
// If truly unused, remove it
// If needed, add usage:
public function getName(): string {
return $this->name;
}
メソッドのエラー
method.notFound — 未定義のメソッド呼び出し
エラー:
Call to an undefined method App\User::getFullName().
修正 — メソッドを追加:
class User {
public function getFullName(): string {
return $this->first_name . ' ' . $this->last_name;
}
}
修正 — マジックメソッドをドキュメントに記載:
/**
* @method string getFullName()
*/
class User {
public function __call($method, $args) { ... }
}
修正(Laravel)— クエリビルダーの @mixin に追加:
/**
* @mixin \Illuminate\Database\Eloquent\Builder
*/
class User extends Model { ... }
配列/オフセットのエラー
offsetAccess.notFound — 未定義の配列オフセット
エラー:
Offset 'email' does not exist on array.
修正 — 配列シェイプの PHPDoc を使用:
/**
* @param array{email: string, name: string} $data
*/
function createUser(array $data): void {
echo $data['email']; // PHPStan knows this exists
}
修正 — 存在確認を追加:
if (isset($data['email'])) {
echo $data['email'];
}
修正 — null 合体演算子を使用:
$email = $data['email'] ?? '[email protected]';
ジェネリック型のエラー
missingType.generics — ジェネリック型がありません
エラー:
Class Collection has @template T but does not specify it.
修正 — PHPDoc でジェネリック型を指定:
// Before
/** @var Collection $users */
$users = User::all();
// After
/** @var Collection<int, User> $users */
$users = User::all();
修正(Laravel)— コレクション用の IDE Helper スタブを使用します。
デッドコードのエラー
deadCode.unreachable — 到達不能なコード
エラー:
Unreachable statement - code above always terminates.
修正 — デッドコードを削除:
// Before
function foo() {
return true;
echo "This never runs"; // Error
}
// After
function foo() {
return true;
}
identical.alwaysTrue / identical.alwaysFalse — 条件が常に true/false です
エラー:
Strict comparison using === between int and string will always evaluate to false.
修正 — 不要な条件を削除するか、型を修正します:
// Before
if ($id === '123') { ... } // $id is int
// After
if ($id === 123) { ... }
フレームワーク固有の修正
Laravel
Laravel に対応した解析を行うため、Larastan をインストールします:
composer require --dev larastan/larastan
phpstan.neon に Larastan が含まれていることを確認します(含まれていない場合は、ユーザーに追加を依頼してください):
includes:
- vendor/larastan/larastan/extension.neon
Laravel でよくある修正:
// Eloquent relationships - use @property PHPDoc
/**
* @property-read \Illuminate\Database\Eloquent\Collection<int, Post> $posts
*/
class User extends Model {
public function posts() {
return $this->hasMany(Post::class);
}
}
// Collections - specify generic types
/** @var \Illuminate\Support\Collection<int, User> $users */
$users = User::all();
// Request input - use typed helpers
$id = $request->integer('id'); // Not $request->input('id')
$email = $request->string('email')->toString();
Symfony
Symfony PHPStan 拡張機能をインストールします:
composer require --dev phpstan/phpstan-symfony
phpstan.neon に Symfony 拡張機能が含まれていることを確認します(含まれていない場合は、ユーザーに追加を依頼してください):
includes:
- vendor/phpstan/phpstan-symfony/extension.neon
parameters:
symfony:
containerXmlPath: var/cache/dev/App_KernelDevDebugContainer.xml
Symfony でよくある修正:
// Service container - use proper type hints
public function __construct(
private UserRepository $userRepository, // Not mixed
) {}
// Forms - type the data
/** @var array{email: string, password: string} $data */
$data = $form->getData();
無視してもよい場合(最終手段)
正当な理由で無視が必要になることもあります。必ず先に Question ツールを使ってユーザーに確認してください:
ステップ 1:状況を説明します
I found a PHPStan error that cannot be easily fixed:
Error: [describe error]
Location: [file:line]
Reason: [explain why it can't be fixed]
ステップ 2:Question ツールを使ってユーザーの選択を確認します
Use the Question tool with these options:
- Header: "PHPStan Error Resolution"
- Question: "How would you like to handle this error?"
- Options:
1. "Use @phpstan-ignore with comment" - description: "Add inline ignore with explanation (recommended for third-party type issues)"
2. "Add to baseline" - description: "Generate baseline file (recommended for legacy code migration)"
3. "Refactor code" - description: "Modify code to satisfy PHPStan (most robust but may require significant changes)"
4. "Skip for now" - description: "Leave unfixed and continue with other errors"
Question ツールの使用例:
{
"questions": [{
"header": "PHPStan Error Resolution",
"question": "File src/Service.php:42 has argument type mismatch with third-party API. How should I handle this?",
"options": [
{
"label": "Use @phpstan-ignore (Recommended)",
"description": "Add inline ignore with explanation"
},
{
"label": "Add to baseline",
"description": "Include in baseline file for tracking"
},
{
"label": "Refactor code",
"description": "Modify to satisfy PHPStan"
},
{
"label": "Skip for now",
"description": "Continue with other errors"
}
]
}]
}
無視が妥当な理由:
- 型に誤りがあるサードパーティライブラリ(利用可能なスタブファイルがない場合)
- 正しいものの、PHPStan が理解できないリフレクションベースのコード
- 実行時には型安全でも、静的には証明できない複雑なビジネスロジック
- 大規模なリファクタリング中の一時的な対応(ベースラインを使用します)
無視する方法(承認された場合):
// Inline ignore with explanation
/** @phpstan-ignore argument.type (API returns string|int, we handle both) */
$result = $api->getValue();
// Baseline for legacy code
vendor/bin/phpstan analyse --generate-baseline
承認なしに、次のことは絶対に行わないでください:
# Don't add this to phpstan.neon without user consent
parameters:
ignoreErrors:
- '#.*#' # NEVER
型のデバッグ
\PHPStan\dumpType() を使って PHPStan の型推論を確認します:
$user = User::find($id);
\PHPStan\dumpType($user); // Reports: App\User|null
// Remove before committing!
トラブルシューティング
PHPStan が有効な型を認識しない
確認事項:
- クラスをオートロードできますか?(
composer dump-autoload) - PHPStan はファイルをスキャンしていますか?(
phpstan.neonのpathsを確認してください) - 名前空間に誤字はありませんか?
型推論が機能しない
確認事項:
- インラインの
@varを使いすぎていませんか?(代わりにソース側で修正してください) - 関数/メソッドの戻り値の型は指定されていますか?
- PHPStan が解析できない動的機能を使っていませんか?
Laravel のマジックメソッドが認識されない
インストールして実行します:
composer require --dev barryvdh/laravel-ide-helper
php artisan ide-helper:generate
php artisan ide-helper:models --write
php artisan ide-helper:meta
エラー識別子のリファレンス
全リスト:https://phpstan.org/error-identifiers
よくあるカテゴリ:
argument.*— 関数/メソッドの引数に関する問題return.*— 戻り値の型の不一致missingType.*— 型宣言の不足property.*— プロパティのアクセス/宣言に関する問題method.*— メソッド呼び出しに関する問題offsetAccess.*— 配列/ArrayAccess に関する問題class.*— クラスの継承/使用に関する問題deadCode.*— 到達不能なコードidentical.*/equal.*— 比較に関する問題