solid-php について
Laravel 13 と PHP 8.3 以降で SOLID と DRY の実践を支援するコーディングスキルです。Laravel または FuseCore のモジュール構成を判別し、コード配置を案内しながら設計上の問題を検出します。
主な機能
- 01Laravel と FuseCore の構成判別
- 02モジュール別コード配置の案内
- 03SOLID リファクタリングの指針
- 04一般的なアンチパターンの検出
- 05PHPDoc とファイル行数の規則
活用シーン
- 01モジュール型 Laravel プロジェクトでのクラス配置
- 02大きなコントローラーやモデルのリファクタリング
- 03依存関係とインターフェース設計の確認
- 04重複ロジックや文書不足の検出
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ fusengine/ claude-plugins --skill solid-phpインストール後、Claude Code で/solid-phpを入力して読み込まれたか確認します。
詳細
Laravel 13 + PHP 8.3 以降のコードに SOLID 原則と DRY を適用します。ファイルはフックの上限 `FUSE_SOLID_MAX_LINES` 以内に収め、インターフェースは FuseCore/[Module]/App/Contracts/(共有インターフェースの場合は FuseCore/Core/App/Contracts/)に分離し、すべての public メソッドに PHPDoc を必須とします。Laravel と FuseCore のモジュラーアーキテクチャを自動検出し、それに応じてコードの配置先(Controllers/Requests/Actions/Services/Repositories/DTOs/Contracts/Events/Policies)を振り分けます。また、アンチパターン(肥大化したクラス、モデル内のビジネスロジック、具象クラスへの依存、strict_types の欠落)を検出し、各 SOLID 原則(SRP/OCP/LSP/ISP/DIP)に沿ったリファクタリングの指針を示します。
1. ファイルは
SOLID PHP - Laravel 13 + PHP 8.3
エージェントのワークフロー(必須)
実装の前に、必ず 3 つのエージェントを並列で起動します。それぞれ name を指定して Agent を 1 回呼び出します。
- fuse-ai-pilot:explore-codebase - 既存のアーキテクチャを分析します
- fuse-ai-pilot:research-expert - Context7 を使って Laravel/PHP のドキュメントを確認します
- mcp__context7__query-docs - SOLID のパターンを確認します
実装後、検証のために fuse-ai-pilot:sniper を実行します。
DRY - 作成する前に再利用(必須)
新しいコードを書く前に、必ず次を行います。
- コードベースを grep して、類似するクラス名、メソッド、ロジックを探します
- 共有配置先を確認します:
FuseCore/Core/App/Services/、FuseCore/Core/App/Traits/、FuseCore/[Module]/App/Contracts/ - 類似コードが存在する場合 → 重複させず、拡張または再利用します
- 2 つ以上の機能で使用するコードの場合 → 共有 Services または Traits に作成します
- 繰り返し出現するロジック(3 回以上)は、共有ヘルパーまたは Traits に抽出します
- コードを書いた後、重複が持ち込まれていないことを確認します
自動検出(モジュラー構成では必須)
| 検出されたファイル | アーキテクチャ | インターフェースの配置先 |
|---|---|---|
FuseCore/ ディレクトリ | FuseCore モジュラー | FuseCore/[Module]/App/Contracts/ |
モジュール内の module.json | FuseCore モジュラー | FuseCore/[Module]/App/Contracts/ |
確認方法:php artisan --version → Laravel 13.x
構成:常に FuseCore モジュラーです。共有コードは FuseCore/Core/App/ に配置します。
決定ツリー:コードの配置先(FuseCore モジュラー)
New code needed?
├── HTTP validation → FuseCore/[Module]/App/Http/Requests/
├── Single action → FuseCore/[Module]/App/Actions/
├── Business logic → FuseCore/[Module]/App/Services/
├── Data access → FuseCore/[Module]/App/Repositories/
├── Data transfer → FuseCore/[Module]/App/DTOs/
├── Interface → FuseCore/[Module]/App/Contracts/
├── Event → FuseCore/[Module]/App/Events/
└── Authorization → FuseCore/[Module]/App/Policies/
決定ツリー:使用するパターン
| 必要な処理 | パターン | 配置先 |
|---|---|---|
| HTTP 処理 | コントローラー | Controllers/ |
| バリデーション | FormRequest | Requests/ |
| 単一の操作 | アクション | Actions/ |
| 複雑なロジック | サービス | Services/ |
| データアクセス | リポジトリ | Repositories/ |
| データ構造 | DTO | DTOs/ |
| 抽象化 | インターフェース | Contracts/ |
重要なルール(必須)
1. ファイルは FUSE_SOLID_MAX_LINES 以内に収める
- フックの上限を大幅に下回る段階で分割します - 回避策を使ってはいけません
- コントローラー:HTTP に関する処理のみ
- モデル:リレーションとキャストのみ
- サービス:ビジネスロジックのみ
2. インターフェースを分離する(FuseCore モジュラーでは必須)
FuseCore/[Module]/App/Contracts/ # Module interfaces ONLY
├── UserRepositoryInterface.php
└── PaymentGatewayInterface.php
FuseCore/Core/App/Contracts/ # Shared interfaces
3. PHPDoc は必須
/**
* Create a new user from DTO.
*
* @param CreateUserDTO $dto User data transfer object
* @return User Created user model
* @throws ValidationException If email already exists
*/
public function create(CreateUserDTO $dto): User
リファレンスガイド
概念
| トピック | リファレンス | 参照するタイミング |
|---|---|---|
| SOLID の概要 | solid-principles.md | すべての原則を手早く確認するとき |
| SRP | single-responsibility.md | ファイルが長すぎる場合、肥大化したコントローラー/モデルがある場合 |
| OCP | open-closed.md | 決済方法やチャネルを追加するとき |
| LSP | liskov-substitution.md | インターフェースの契約やプロバイダーの切り替えを確認するとき |
| ISP | interface-segregation.md | 肥大化したインターフェースや未使用のメソッドがある場合 |
| DIP | dependency-inversion.md | 密結合、テスト、モックを確認するとき |
| アンチパターン | anti-patterns.md | コードの不吉な兆候を検出するとき |
| 判断基準 | decision-guide.md | パターンを選択するとき |
| PHP 8.5 | php85-features.md | 最新の PHP 機能を確認するとき |
| 構造 | laravel12-structure.md | 標準的な Laravel の構造を確認するとき |
| FuseCore | fusecore-structure.md | モジュール型アーキテクチャを確認するとき |
テンプレート
| テンプレート | 使用するタイミング |
|---|---|
| code-templates.md | Service、DTO、Repository、Interface |
| controller-templates.md | Controller、Action、FormRequest、Policy |
| refactoring-guide.md | レガシーコードから段階的に移行するとき |
禁止事項
| アンチパターン | 検出方法 | 修正方法 |
|---|---|---|
FUSE_SOLID_MAX_LINES を超えるファイル | 行数 | ファイルを小さく分割する |
| ビジネスロジックを含むコントローラー | コードレビュー | Service に抽出する |
| impl ファイル内のインターフェース | 配置場所 | FuseCore/[Module]/App/Contracts/ に移動する |
| モデル内のビジネスロジック | モデル内のコード | Service に抽出する |
| 具体クラスへの依存 | new Class() | ModuleServiceProvider を介して注入する |
| PHPDoc がない | ドキュメントブロックがない | ドキュメントを追加する |
| strict_types がない | declare がない | すべてのファイルに追加する |
| 肥大化したクラス | 5 個を超える public メソッド | 責務を分割する |
| ロジックの重複 | 2 つ以上のファイルに同じコードがある | Service/Trait に抽出する |
| コーディング前に Grep しない | 検索せずに作成する | まずコードベースを Grep する |
ベストプラクティス
| すること | しないこと |
|---|---|
| コンストラクターのプロパティプロモーションを使用する | プロパティ代入を使用する |
| インターフェースに依存する | 具体クラスに依存する |
final readonly class を使用する | 可変クラスを使用する |
declare(strict_types=1) を使用する | 型宣言を省略する |
FUSE_SOLID_MAX_LINES に達する前に十分な余裕を持って分割する | フックによってブロックされるまで待つ |
| データ転送に DTO を使用する | 配列を使用する |
Laravel 13 に関する注意事項
PHP 8.3 以上
Laravel 13 には PHP 8.3 が必要です(L12 では 8.2 でした)。SOLID に役立つ機能:
readonlyクラス:final readonly class UserDto(完全な不変性)- 型付きクラス定数:
const int MAX_RETRIES = 3; #[\Override]属性:親メソッドをオーバーライドすることを明示的に宣言します(タイプミスを検出します)- ネイティブの
json_validate()(json_decodeと try/catch の組み合わせより高速) - 動的なクラス定数の取得:
$class::{$name}
use Override;
final readonly class PaymentService implements PaymentContract
{
public const int DEFAULT_TIMEOUT = 30;
public function __construct(
private StripeClient $stripe,
private LoggerInterface $logger,
) {}
#[Override]
public function process(PaymentDto $payment): PaymentResult
{
// ...
}
}
L13 のより厳格な SOLID ルール
- すべての DTO/Value Object で
final readonly classを優先する - 継承したすべてのメソッドに
#[\Override]を使用する(CI で検出されます) - 定数に型を指定する(
const string ROLE = 'admin';)
コメント
Markdown 対応