mcpField
P
phpstan-fixer

phpstan-fixer

github.com/marcelorodrigoテスト・品質19113 回インストール8 週間前に更新
リポジトリ

phpstan-fixer について

PHPStanの静的解析エラーを、型注釈やPHPDoc、コードの改善で修正するためのエージェント向けスキルです。根本原因への対処、プロジェクト設定の尊重、第三者コードを変更しない方針を重視します。

主な機能

  1. 01PHPStanエラーの文脈分析
  2. 02型とPHPDocの修正
  3. 03設定済みの厳格度の尊重
  4. 04未承認のエラー抑制を回避
  5. 05スタブによる第三者型の補正
  6. 06PHPStanで変更を検証

活用シーン

  1. 01不足している型宣言の補完
  2. 02引数と戻り値の型の修正
  3. 03フレームワーク固有の型問題への対応
  4. 04vendorライブラリの型エラーへの対処

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/marcelorodrigo/agent-skills --skill phpstan-fixer

インストール後、Claude Code で/phpstan-fixerを入力して読み込まれたか確認します。

詳細

PHPStan エラー修正ツール

適切な型注釈、PHPDoc、コードの改善を通じて、PHPStan の静的解析エラーを修正します。このスキルでは、プロジェクトに設定された厳格さのレベルを尊重しながら、エラーを抑制せずに解決する方法をエージェントに教えます。

基本原則

  1. 最初の手段としてエラーを抑制しない — 適切な型と注釈を使って根本原因を修正します
  2. ユーザーの設定を尊重する — phpstan.neon の設定(レベル、パス、パラメーター)は変更しません
  3. 黙って無視しない — ユーザーの明示的な承認なしに、設定に ignoreErrors を追加しません
  4. コンテキストを考慮して修正する — 解決策を提案する前に、プロジェクトの種類(Laravel、Symfony、素の PHP)を把握します
  5. 無視する前に確認する — 正当な理由でエラーを無視する必要がある場合は、その理由を説明し、先にユーザーの承認を得ます
  6. サードパーティーのコードは修正しない — 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
------ ----------------------------------------------

抽出する情報:

  1. エラー識別子(例:parameter.type、missingType.return)
  2. エラーの場所(ファイル、行番号)
  3. コンテキスト(このコードは何をしようとしていますか?)
ステップ 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 が有効な型を認識しない

確認事項:

  1. クラスをオートロードできますか?(composer dump-autoload)
  2. PHPStan はファイルをスキャンしていますか?(phpstan.neon の paths を確認してください)
  3. 名前空間に誤字はありませんか?
型推論が機能しない

確認事項:

  1. インラインの @var を使いすぎていませんか?(代わりにソース側で修正してください)
  2. 関数/メソッドの戻り値の型は指定されていますか?
  3. 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.* — 比較に関する問題

リソース

コメント