Claude Code PHP開発活用法|Laravel・WordPress自動化
Claude Codeは、PHPプロジェクトでも圧倒的な開発効率を発揮します。Laravel・WordPressをはじめとするPHPフレームワークでのコード生成、PHPStanによる静的解析の自動化、PHPUnitテストの一括生成まで、この記事ではPHP開発者がClaude Codeを最大限に活用するための設定方法と実践テクニックを、実際のコード例とともに徹底解説します。
目次
1. PHPプロジェクト向けCLAUDE.mdの最適設定
Claude Codeの出力品質を大きく左右するのがCLAUDE.mdファイルです。PHPプロジェクトでは、使用するフレームワーク・PHPバージョン・コーディング規約・ディレクトリ構造を明記することで、生成コードの精度が飛躍的に向上します。
PHPプロジェクト向けCLAUDE.mdの完全テンプレート
以下は、PHP(Laravel)プロジェクト向けのCLAUDE.mdテンプレートです。プロジェクトルートに配置してください。
# プロジェクト設定
## 技術スタック
- PHP 8.3
- Laravel 11
- MySQL 8.0
- Redis 7
- Node.js 20(フロントエンド)
## ディレクトリ構造
- app/Models/ - Eloquentモデル
- app/Http/Controllers/ - コントローラ
- app/Services/ - ビジネスロジック
- app/Repositories/ - データアクセス層
- database/migrations/ - マイグレーション
- tests/Unit/ - ユニットテスト
- tests/Feature/ - 機能テスト
## コーディング規約
- PSR-12 準拠
- 厳密な型宣言を使用: declare(strict_types=1)
- メソッドには必ず戻り値の型を宣言する
- プロパティには必ず型宣言を付ける
- PHPStan レベル8で解析をパスすること
- PHP CS Fixer(.php-cs-fixer.php)に従うこと
## 禁止事項
- dd()やdump()を本番コードに残さない
- env()をconfig以外で直接呼ばない
- SQLの直接組み立て禁止(Eloquent/QueryBuilder必須)
- anyを使った型回避禁止
## テスト規約
- テストクラス名: {対象クラス名}Test
- テストメソッド名: test_{動作の説明}
- 各テストにはアサーションを必ず含める
- モックは Mockery を使用
- テスト実行: php artisan test
## コマンド
- 構文チェック: php -l {ファイル}
- 静的解析: ./vendor/bin/phpstan analyse
- テスト: php artisan test
- フォーマット: ./vendor/bin/php-cs-fixer fix
CLAUDE.mdは プロジェクトルートに配置します。Claude Codeは起動時にこのファイルを自動的に読み込み、記載されたルールに従ってコードを生成します。グローバル設定は~/.claude/CLAUDE.mdに配置できます。
フレームワーク別のCLAUDE.md設定ポイント
Laravel
- Eloquentモデルのリレーション方針
- FormRequestバリデーション必須
- Service層の責務範囲
- API Resource/Collectionの使い方
WordPress
- WordPress Coding Standards準拠
- nonce検証・エスケープ関数の使い方
- フック(action/filter)の命名規則
- $wpdb->prepare() 必須
Symfony
- サービスコンテナの設定方針
- Doctrine Entityの設計規約
- Twig テンプレートの規約
- Messenger/Event の活用方針
API開発(Slim/Lumen)
- ルーティング設計のルール
- ミドルウェアの適用方針
- JSONレスポンス形式の統一
- 認証方式(JWT/OAuth等)の指定
2. PHPプロジェクトでClaude Codeを始める手順
Claude Codeを既存のPHPプロジェクトで使い始めるための具体的な手順を解説します。新規プロジェクトでも既存プロジェクトでも、以下の流れで進めてください。
Step 1: Claude Codeのインストール
まだClaude Codeをインストールしていない場合は、以下のコマンドを実行します。
# Claude Codeのインストール
npm install -g @anthropic-ai/claude-code
# バージョン確認
claude --version
Claude Codeの詳しいインストール手順は「Claude Code入門ガイド」を参照してください。
Step 2: PHPプロジェクトで起動する
PHPプロジェクトのルートディレクトリでClaude Codeを起動します。
# プロジェクトルートに移動
cd /path/to/your-laravel-project
# Claude Codeを起動
claude
# Claude Codeが自動的にプロジェクト構造を認識
# - composer.json からフレームワークとパッケージを検出
# - CLAUDE.md からプロジェクトルールを読み込み
# - .phpstan.neon / phpstan.neon.dist から静的解析設定を認識
Step 3: PHPStan・PHP CS Fixerを導入する
コード品質を担保するために、静的解析ツールとコードフォーマッターを導入します。これらがあるとClaude Codeが生成後に自動チェックできます。
# PHPStan(静的解析)のインストール
composer require --dev phpstan/phpstan
composer require --dev phpstan/phpstan-strict-rules
# Laravel用の拡張
composer require --dev larastan/larastan
# PHP CS Fixer(フォーマッター)のインストール
composer require --dev friendsofphp/php-cs-fixer
# PHPUnit(テスト)は通常Laravelに同梱済み
# Laravelでない場合:
composer require --dev phpunit/phpunit
Step 4: PHPStan設定ファイルを作成する
プロジェクトルートにphpstan.neonを配置します。Claude Codeはこの設定を自動認識します。
# phpstan.neon(Laravelプロジェクト向け)
includes:
- vendor/larastan/larastan/extension.neon
parameters:
paths:
- app/
level: 8
ignoreErrors:
# 必要に応じてエラーを除外
excludePaths:
- app/Http/Middleware/
checkMissingIterableValueType: false
Step 5: 最初のタスクを実行する
準備が整ったら、Claude Codeに最初のタスクを指示してみましょう。
# Claude Codeへの指示例
> app/Models/User.php を確認して、
プロフィール更新機能を追加してください。
Service層・FormRequest・テストも作成してください。
Claude Codeは以下の順序で作業を進めます。
- 既存のコードを読み取り、プロジェクトの構造やコーディングスタイルを理解する
- CLAUDE.mdのルールに従い、必要なファイルを生成する
php -lで構文チェックを実行する- PHPStanで静的解析を実行し、エラーがあれば自動修正する
- テストを実行して動作を確認する
3. Laravel開発でClaude Codeを使う実践チュートリアル
Laravelは日本のPHP開発者に最も人気のあるフレームワークです。Claude Codeとの相性は非常に良く、Eloquent・マイグレーション・テスト・APIリソースなどの生成を高い精度で行えます。ここでは実際のユースケースに沿って解説します。
3-1. CRUD機能の一括生成
Claude Codeに以下のように指示するだけで、Model・Migration・Controller・FormRequest・Resource・テストを一括生成できます。
# Claude Codeへの指示
> 「商品管理」機能を作成してください。
- Productモデル(name, price, description, stock, status)
- マイグレーション
- ProductController(CRUD)
- StoreProductRequest / UpdateProductRequest
- ProductResource / ProductCollection
- Unit/Featureテスト
- Laravel 11のルーティング形式で
Claude Codeが生成するコードの例を見てみましょう。
<?php
// app/Models/Product.php
declare(strict_types=1);
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
/**
* @property int $id
* @property string $name
* @property int $price
* @property string|null $description
* @property int $stock
* @property string $status
*/
class Product extends Model
{
use HasFactory;
use SoftDeletes;
protected $fillable = [
'name',
'price',
'description',
'stock',
'status',
];
protected $casts = [
'price' => 'integer',
'stock' => 'integer',
];
public function scopeActive(
\Illuminate\Database\Eloquent\Builder $query
): \Illuminate\Database\Eloquent\Builder {
return $query->where('status', 'active');
}
}
<?php
// app/Http/Requests/StoreProductRequest.php
declare(strict_types=1);
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class StoreProductRequest extends FormRequest
{
public function authorize(): bool
{
return true;
}
/**
* @return array<string, array<int, string>>
*/
public function rules(): array
{
return [
'name' => ['required', 'string', 'max:255'],
'price' => ['required', 'integer', 'min:0'],
'description' => ['nullable', 'string', 'max:5000'],
'stock' => ['required', 'integer', 'min:0'],
'status' => ['required', 'in:active,inactive,draft'],
];
}
/**
* @return array<string, string>
*/
public function messages(): array
{
return [
'name.required' => '商品名は必須です。',
'price.required' => '価格は必須です。',
'price.min' => '価格は0以上で入力してください。',
];
}
}
3-2. Eloquentリレーションの構築
複雑なリレーションもClaude Codeに自然言語で指示できます。
# Claude Codeへの指示
> User hasMany Order、Order belongsTo User、
Order hasMany OrderItem、OrderItem belongsTo Product
のリレーションを構築してください。
Eager Loading用のスコープも作成してください。
<?php
// 生成されるリレーション例(app/Models/Order.php)
declare(strict_types=1);
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\Builder;
class Order extends Model
{
protected $fillable = ['user_id', 'total', 'status'];
public function user(): BelongsTo
{
return $this->belongsTo(User::class);
}
public function items(): HasMany
{
return $this->hasMany(OrderItem::class);
}
/**
* Eager Loading用スコープ
*/
public function scopeWithDetails(Builder $query): Builder
{
return $query->with([
'user:id,name,email',
'items.product:id,name,price',
]);
}
}
3-3. APIエンドポイントの作成
RESTful APIの実装もClaude Codeの得意分野です。
# Claude Codeへの指示
> 商品APIを作成してください。
- GET /api/products(一覧・ページネーション・検索・ソート)
- GET /api/products/{id}(詳細)
- POST /api/products(作成・認証必須)
- PUT /api/products/{id}(更新・認証必須)
- DELETE /api/products/{id}(削除・認証必須)
- API Resourceを使ったレスポンス統一
- Sanctum認証
<?php
// app/Http/Controllers/Api/ProductController.php
declare(strict_types=1);
namespace App\Http\Controllers\Api;
use App\Http\Controllers\Controller;
use App\Http\Requests\StoreProductRequest;
use App\Http\Requests\UpdateProductRequest;
use App\Http\Resources\ProductCollection;
use App\Http\Resources\ProductResource;
use App\Models\Product;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
class ProductController extends Controller
{
public function index(Request $request): ProductCollection
{
$query = Product::query();
// 検索
if ($search = $request->input('search')) {
$query->where('name', 'like', "%{$search}%");
}
// ステータスフィルタ
if ($status = $request->input('status')) {
$query->where('status', $status);
}
// ソート
$sortBy = $request->input('sort_by', 'created_at');
$sortDir = $request->input('sort_dir', 'desc');
$query->orderBy($sortBy, $sortDir);
return new ProductCollection(
$query->paginate($request->input('per_page', 15))
);
}
public function store(
StoreProductRequest $request
): JsonResponse {
$product = Product::create($request->validated());
return (new ProductResource($product))
->response()
->setStatusCode(201);
}
public function show(Product $product): ProductResource
{
return new ProductResource($product);
}
public function update(
UpdateProductRequest $request,
Product $product
): ProductResource {
$product->update($request->validated());
return new ProductResource($product);
}
public function destroy(Product $product): JsonResponse
{
$product->delete();
return response()->json(null, 204);
}
}
3-4. マイグレーション・Seederの生成
データベース関連のコードも自然言語で指示できます。
# Claude Codeへの指示
> productsテーブルにcategory_idカラムを追加する
マイグレーションを作成してください。
categoriesテーブルへの外部キー制約付きで、
既存データにはデフォルトカテゴリを設定してください。
<?php
// database/migrations/2026_03_17_add_category_id_to_products.php
declare(strict_types=1);
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
use Illuminate\Support\Facades\DB;
return new class extends Migration
{
public function up(): void
{
Schema::table('products', function (Blueprint $table) {
$table->foreignId('category_id')
->nullable()
->after('name')
->constrained()
->nullOnDelete();
});
// 既存データにデフォルトカテゴリを設定
$defaultCategory = DB::table('categories')
->where('slug', 'uncategorized')
->first();
if ($defaultCategory) {
DB::table('products')
->whereNull('category_id')
->update(['category_id' => $defaultCategory->id]);
}
}
public function down(): void
{
Schema::table('products', function (Blueprint $table) {
$table->dropForeign(['category_id']);
$table->dropColumn('category_id');
});
}
};
4. WordPress開発でのAI活用パターン
WordPress開発にもClaude Codeは強力なパートナーです。プラグイン開発・テーマカスタマイズ・カスタムブロック作成・REST API拡張など、WordPressの複雑なエコシステムをClaude Codeが理解した上でコードを生成します。
4-1. WordPress向けCLAUDE.mdの設定
# WordPress プラグイン開発 - CLAUDE.md
## 技術スタック
- WordPress 6.7
- PHP 8.2
- MySQL 8.0
## コーディング規約
- WordPress Coding Standards(WPCS)準拠
- プラグインプレフィックス: myplugin_
- テキストドメイン: my-plugin
- すべてのユーザー入力をサニタイズする
- 出力は必ずエスケープする(esc_html, esc_attr, wp_kses)
## セキュリティルール
- nonce検証: wp_verify_nonce() / check_admin_referer()
- 権限チェック: current_user_can() を必ず使用
- DB操作: $wpdb->prepare() 必須
- ファイルアップロード: wp_handle_upload() 使用
## 禁止事項
- extract() の使用禁止
- eval() の使用禁止
- 直接的なSQL文の組み立て禁止
- $_GET/$_POST の直接echo禁止
4-2. カスタム投稿タイプとメタボックスの作成
Claude Codeにカスタム投稿タイプの作成を指示する例です。
# Claude Codeへの指示
> 「イベント」カスタム投稿タイプを作成してください。
- カスタムフィールド: 開催日、場所、定員、参加費
- メタボックス付き
- 管理画面カラムにカスタムフィールドを表示
- アーカイブページ対応
- WordPressコーディング規約準拠
<?php
/**
* Plugin Name: Event Manager
* Description: イベント管理プラグイン
* Version: 1.0.0
* Text Domain: event-manager
*/
declare(strict_types=1);
defined('ABSPATH') || exit;
/**
* カスタム投稿タイプ「イベント」を登録
*/
function em_register_event_post_type(): void {
$labels = array(
'name' => __('イベント', 'event-manager'),
'singular_name' => __('イベント', 'event-manager'),
'add_new' => __('新規追加', 'event-manager'),
'add_new_item' => __('新規イベントを追加', 'event-manager'),
'edit_item' => __('イベントを編集', 'event-manager'),
'view_item' => __('イベントを表示', 'event-manager'),
'all_items' => __('すべてのイベント', 'event-manager'),
'search_items' => __('イベントを検索', 'event-manager'),
);
$args = array(
'labels' => $labels,
'public' => true,
'has_archive' => true,
'rewrite' => array('slug' => 'events'),
'supports' => array('title', 'editor', 'thumbnail'),
'menu_icon' => 'dashicons-calendar-alt',
'show_in_rest' => true,
);
register_post_type('event', $args);
}
add_action('init', 'em_register_event_post_type');
/**
* イベント詳細メタボックスを追加
*/
function em_add_event_meta_boxes(): void {
add_meta_box(
'em_event_details',
__('イベント詳細', 'event-manager'),
'em_render_event_meta_box',
'event',
'normal',
'high'
);
}
add_action('add_meta_boxes', 'em_add_event_meta_boxes');
/**
* メタボックスのHTML出力
*/
function em_render_event_meta_box(\WP_Post $post): void {
wp_nonce_field('em_save_event', 'em_event_nonce');
$event_date = get_post_meta($post->ID, '_em_event_date', true);
$location = get_post_meta($post->ID, '_em_location', true);
$capacity = get_post_meta($post->ID, '_em_capacity', true);
$fee = get_post_meta($post->ID, '_em_fee', true);
?>
<table class="form-table">
<tr>
<th><label for="em_event_date">
<?php esc_html_e('開催日', 'event-manager'); ?>
</label></th>
<td><input type="date" id="em_event_date"
name="em_event_date"
value="<?php echo esc_attr($event_date); ?>"></td>
</tr>
<tr>
<th><label for="em_location">
<?php esc_html_e('場所', 'event-manager'); ?>
</label></th>
<td><input type="text" id="em_location"
name="em_location" class="regular-text"
value="<?php echo esc_attr($location); ?>"></td>
</tr>
<tr>
<th><label for="em_capacity">
<?php esc_html_e('定員', 'event-manager'); ?>
</label></th>
<td><input type="number" id="em_capacity"
name="em_capacity" min="0"
value="<?php echo esc_attr($capacity); ?>"></td>
</tr>
<tr>
<th><label for="em_fee">
<?php esc_html_e('参加費', 'event-manager'); ?>
</label></th>
<td><input type="number" id="em_fee"
name="em_fee" min="0"
value="<?php echo esc_attr($fee); ?>"></td>
</tr>
</table>
<?php
}
/**
* メタデータの保存
*/
function em_save_event_meta(int $post_id): void {
// nonce検証
if (
! isset($_POST['em_event_nonce']) ||
! wp_verify_nonce(
sanitize_text_field(
wp_unslash($_POST['em_event_nonce'])
),
'em_save_event'
)
) {
return;
}
// 自動保存をスキップ
if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) {
return;
}
// 権限チェック
if (! current_user_can('edit_post', $post_id)) {
return;
}
$fields = array(
'_em_event_date' => 'sanitize_text_field',
'_em_location' => 'sanitize_text_field',
'_em_capacity' => 'absint',
'_em_fee' => 'absint',
);
foreach ($fields as $key => $sanitize_fn) {
$field_name = str_replace('_em_', 'em_', $key);
if (isset($_POST[$field_name])) {
$value = wp_unslash($_POST[$field_name]);
update_post_meta(
$post_id,
$key,
$sanitize_fn($value)
);
}
}
}
add_action('save_post_event', 'em_save_event_meta');
Claude Codeが生成したWordPressコードは、nonce検証・権限チェック・サニタイズ・エスケープなどのセキュリティベストプラクティスを自動的に含みます。CLAUDE.mdでセキュリティルールを明記しておくことで、さらに確実になります。
4-3. REST API拡張
WordPress REST APIのカスタムエンドポイント追加もClaude Codeで簡単です。
# Claude Codeへの指示
> WordPressのREST APIに /wp-json/em/v1/events
エンドポイントを追加してください。
- 一覧取得(ページネーション対応)
- 日付範囲フィルタ
- 認証必須のPOSTエンドポイント
<?php
/**
* REST APIエンドポイント登録
*/
function em_register_rest_routes(): void {
register_rest_route('em/v1', '/events', array(
array(
'methods' => 'GET',
'callback' => 'em_get_events',
'permission_callback' => '__return_true',
'args' => array(
'page' => array(
'default' => 1,
'sanitize_callback' => 'absint',
),
'per_page' => array(
'default' => 10,
'sanitize_callback' => 'absint',
),
'from' => array(
'sanitize_callback' => 'sanitize_text_field',
),
'to' => array(
'sanitize_callback' => 'sanitize_text_field',
),
),
),
array(
'methods' => 'POST',
'callback' => 'em_create_event',
'permission_callback' => function () {
return current_user_can('publish_posts');
},
),
));
}
add_action('rest_api_init', 'em_register_rest_routes');
/**
* イベント一覧を取得
*/
function em_get_events(\WP_REST_Request $request): \WP_REST_Response {
$args = array(
'post_type' => 'event',
'posts_per_page' => $request->get_param('per_page'),
'paged' => $request->get_param('page'),
'orderby' => 'meta_value',
'meta_key' => '_em_event_date',
'order' => 'ASC',
);
// 日付範囲フィルタ
$meta_query = array();
$from = $request->get_param('from');
$to = $request->get_param('to');
if ($from) {
$meta_query[] = array(
'key' => '_em_event_date',
'value' => sanitize_text_field($from),
'compare' => '>=',
'type' => 'DATE',
);
}
if ($to) {
$meta_query[] = array(
'key' => '_em_event_date',
'value' => sanitize_text_field($to),
'compare' => '<=',
'type' => 'DATE',
);
}
if (! empty($meta_query)) {
$args['meta_query'] = $meta_query;
}
$query = new \WP_Query($args);
$events = array();
foreach ($query->posts as $post) {
$events[] = array(
'id' => $post->ID,
'title' => $post->post_title,
'date' => get_post_meta(
$post->ID, '_em_event_date', true
),
'location' => get_post_meta(
$post->ID, '_em_location', true
),
'capacity' => (int) get_post_meta(
$post->ID, '_em_capacity', true
),
'fee' => (int) get_post_meta(
$post->ID, '_em_fee', true
),
);
}
return new \WP_REST_Response(array(
'events' => $events,
'total' => $query->found_posts,
'pages' => $query->max_num_pages,
), 200);
}
4-4. 既存テーマのカスタマイズ
子テーマの作成やfunctions.phpのカスタマイズもClaude Codeで効率化できます。
# Claude Codeへの指示
> Twenty Twenty-Fourの子テーマを作成してください。
- カスタムヘッダー・フッター
- OGP自動出力機能
- パンくずリスト機能
- 構造化データ(JSON-LD)自動出力
5. PHPStanとClaude Codeで型安全性を向上させる
PHPStanは静的解析ツールで、実行前にコードのバグを検出できます。Claude CodeとPHPStanを組み合わせることで、型安全なPHPコードを効率的に書けるようになります。
5-1. PHPStanレベルの解説
| レベル | チェック内容 | 推奨 |
|---|---|---|
| 0 | 基本的なチェック(未定義変数など) | 入門 |
| 1-3 | 型の不一致、不要なキャスト、未定義メソッド | レガシー |
| 4-5 | 戻り値の型、dead code検出 | 標準 |
| 6-7 | union型の厳密チェック、引数の型安全 | 推奨 |
| 8-9 | nullable型、mixed型の制限、完全な型安全 | 厳密 |
5-2. Claude CodeでPHPStanエラーを自動修正する
Claude Codeに「PHPStanのエラーを修正して」と指示するだけで、エラーの解析から修正まで自動で行われます。
# Claude Codeへの指示
> ./vendor/bin/phpstan analyse を実行して、
報告されたエラーをすべて修正してください。
Claude Codeは以下のように動作します。
# Claude Codeの作業フロー
$ ./vendor/bin/phpstan analyse
------ -------------------------------------------------
Line app/Services/OrderService.php
------ -------------------------------------------------
45 Parameter #1 $price of method calculateTax()
expects int, string given.
78 Method getTotal() should return int but returns
int|null.
------ -------------------------------------------------
# Claude Codeが自動修正
# 1. $price の型をintにキャスト
# 2. getTotal() の戻り値型を int|null に変更、
# またはnullチェックを追加
# 修正後に再度PHPStanを実行して確認
$ ./vendor/bin/phpstan analyse
# [OK] No errors
5-3. レガシーコードの型安全化
型宣言のないレガシーPHPコードをClaude Codeで段階的に型安全にする戦略です。
# Claude Codeへの指示(段階的アプローチ)
> app/Services/PaymentService.php に対して、
以下の順序で型安全化を行ってください。
1. declare(strict_types=1) を追加
2. メソッド引数に型宣言を追加
3. 戻り値の型宣言を追加
4. プロパティの型宣言を追加
5. PHPDocの @var/@param/@return を更新
6. phpstan analyse --level 8 でエラーがないこと
<?php
// Before: 型宣言なしのレガシーコード
class PaymentService
{
private $gateway;
private $logger;
public function __construct($gateway, $logger)
{
$this->gateway = $gateway;
$this->logger = $logger;
}
public function charge($amount, $currency, $token)
{
$result = $this->gateway->charge($amount, $currency, $token);
$this->logger->info('Payment charged', $result);
return $result;
}
}
// After: Claude Codeによる型安全化
declare(strict_types=1);
class PaymentService
{
public function __construct(
private readonly PaymentGatewayInterface $gateway,
private readonly LoggerInterface $logger,
) {
}
/**
* @throws PaymentFailedException
*/
public function charge(
int $amount,
string $currency,
string $token
): PaymentResult {
$result = $this->gateway->charge(
$amount, $currency, $token
);
$this->logger->info('Payment charged', [
'amount' => $amount,
'currency' => $currency,
'transaction_id' => $result->getTransactionId(),
]);
return $result;
}
}
5-4. PHPDoc生成の自動化
既存コードにPHPDocを一括追加することもClaude Codeで可能です。
# Claude Codeへの指示
> app/Services/ 配下のすべてのクラスに
PHPDocを追加してください。
- クラスの概要説明
- @param, @return, @throws
- PHPStan用の @template, @extends 等
- 配列の型は array<string, mixed> 形式で記載
6. PHPUnitテスト自動生成の実践例
テスト作成は開発者にとって時間のかかる作業ですが、Claude Codeを使えばテストコードを高速に生成できます。ユニットテスト・機能テスト・統合テストのいずれにも対応します。
6-1. 基本的なユニットテストの自動生成
# Claude Codeへの指示
> app/Services/PriceCalculator.php のユニットテストを
作成してください。
- 正常系・異常系・境界値をカバー
- データプロバイダを活用
- カバレッジ100%を目指す
<?php
// tests/Unit/Services/PriceCalculatorTest.php
declare(strict_types=1);
namespace Tests\Unit\Services;
use App\Services\PriceCalculator;
use InvalidArgumentException;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\TestCase;
class PriceCalculatorTest extends TestCase
{
private PriceCalculator $calculator;
protected function setUp(): void
{
parent::setUp();
$this->calculator = new PriceCalculator();
}
#[Test]
public function test_calculate_tax_with_standard_rate(): void
{
$result = $this->calculator->calculateTax(1000, 0.10);
$this->assertSame(100, $result);
}
#[Test]
public function test_calculate_tax_with_reduced_rate(): void
{
$result = $this->calculator->calculateTax(1000, 0.08);
$this->assertSame(80, $result);
}
#[Test]
#[DataProvider('priceWithDiscountProvider')]
public function test_apply_discount(
int $price,
int $discountPercent,
int $expected
): void {
$result = $this->calculator->applyDiscount(
$price, $discountPercent
);
$this->assertSame($expected, $result);
}
/**
* @return array<string, array{int, int, int}>
*/
public static function priceWithDiscountProvider(): array
{
return [
'10%割引' => [1000, 10, 900],
'20%割引' => [1000, 20, 800],
'50%割引' => [1000, 50, 500],
'割引なし' => [1000, 0, 1000],
'100%割引' => [1000, 100, 0],
];
}
#[Test]
public function test_throws_exception_for_negative_price(): void
{
$this->expectException(InvalidArgumentException::class);
$this->expectExceptionMessage('Price must be non-negative');
$this->calculator->calculateTax(-100, 0.10);
}
#[Test]
public function test_throws_exception_for_invalid_discount(): void
{
$this->expectException(InvalidArgumentException::class);
$this->calculator->applyDiscount(1000, 150);
}
// 境界値テスト
#[Test]
public function test_zero_price(): void
{
$this->assertSame(
0, $this->calculator->calculateTax(0, 0.10)
);
}
#[Test]
public function test_large_price(): void
{
$result = $this->calculator->calculateTax(
PHP_INT_MAX, 0.10
);
$this->assertIsInt($result);
}
}
6-2. Laravelの機能テスト(Feature Test)
# Claude Codeへの指示
> ProductControllerのFeatureテストを作成してください。
- 認証済み/未認証ユーザーの動作確認
- バリデーションエラーのテスト
- データベースへの保存確認
- JSONレスポンスの構造確認
<?php
// tests/Feature/Api/ProductControllerTest.php
declare(strict_types=1);
namespace Tests\Feature\Api;
use App\Models\Product;
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use PHPUnit\Framework\Attributes\Test;
use Tests\TestCase;
class ProductControllerTest extends TestCase
{
use RefreshDatabase;
private User $user;
protected function setUp(): void
{
parent::setUp();
$this->user = User::factory()->create();
}
#[Test]
public function test_can_list_products(): void
{
Product::factory()->count(5)->create();
$response = $this->getJson('/api/products');
$response->assertOk()
->assertJsonCount(5, 'data')
->assertJsonStructure([
'data' => [
'*' => ['id', 'name', 'price', 'status'],
],
'meta' => ['current_page', 'total'],
]);
}
#[Test]
public function test_authenticated_user_can_create(): void
{
$payload = [
'name' => 'テスト商品',
'price' => 3000,
'description' => '説明文',
'stock' => 10,
'status' => 'active',
];
$response = $this->actingAs($this->user)
->postJson('/api/products', $payload);
$response->assertCreated()
->assertJsonPath('data.name', 'テスト商品');
$this->assertDatabaseHas('products', [
'name' => 'テスト商品',
'price' => 3000,
]);
}
#[Test]
public function test_unauthenticated_user_cannot_create(): void
{
$response = $this->postJson('/api/products', [
'name' => 'テスト商品',
]);
$response->assertUnauthorized();
}
#[Test]
public function test_validation_error_on_invalid_data(): void
{
$response = $this->actingAs($this->user)
->postJson('/api/products', [
'name' => '',
'price' => -100,
]);
$response->assertUnprocessable()
->assertJsonValidationErrors([
'name', 'price', 'stock', 'status',
]);
}
#[Test]
public function test_can_search_products(): void
{
Product::factory()->create(['name' => 'Laravel本']);
Product::factory()->create(['name' => 'PHP入門']);
$response = $this->getJson(
'/api/products?search=Laravel'
);
$response->assertOk()
->assertJsonCount(1, 'data')
->assertJsonPath('data.0.name', 'Laravel本');
}
#[Test]
public function test_can_delete_product(): void
{
$product = Product::factory()->create();
$response = $this->actingAs($this->user)
->deleteJson("/api/products/{$product->id}");
$response->assertNoContent();
$this->assertSoftDeleted('products', [
'id' => $product->id,
]);
}
}
6-3. テストカバレッジの向上
Claude Codeにカバレッジレポートを渡して、不足しているテストを追加させることもできます。
# カバレッジレポート生成
php artisan test --coverage-html=coverage/
# Claude Codeへの指示
> coverage/ のHTMLレポートを確認して、
カバレッジが80%未満のクラスに対して
テストを追加してください。
特にapp/Services/ のカバレッジを重点的に改善してください。
7. Composer連携と依存管理の自動化
Claude CodeはComposerと連携して、パッケージの追加・更新・設定を自動化できます。必要なライブラリを自然言語で伝えるだけで、インストールからコードへの組み込みまで一貫して行います。
7-1. パッケージ追加とコード実装の一括実行
# Claude Codeへの指示
> Stripe決済機能を追加してください。
- stripe/stripe-php パッケージをインストール
- 設定ファイルにStripeキーを追加
- PaymentServiceを作成
- 決済・返金・Webhook処理を実装
- テストも作成
Claude Codeは以下の順序で処理を進めます。
composer require stripe/stripe-phpを実行config/services.phpにStripe設定を追加app/Services/StripePaymentService.phpを作成- Webhookコントローラを作成
- ルーティングを追加
- テストを作成・実行
7-2. セキュリティアップデート
# Claude Codeへの指示
> composer audit を実行して、
脆弱性のあるパッケージをアップデートしてください。
後方互換性に問題がある場合は報告してください。
# Claude Codeの実行例
$ composer audit
Found 2 security vulnerability advisories:
- guzzlehttp/guzzle (7.5.0) - CVE-2023-XXXX
- symfony/http-kernel (6.3.0) - CVE-2024-XXXX
$ composer update guzzlehttp/guzzle symfony/http-kernel
# アップデート後にテスト実行
$ php artisan test
# Tests: 156 passed
7-3. Composerスクリプトの設定
CLAUDE.mdにComposerスクリプトを定義しておくと、Claude Codeが品質チェックに活用します。
// composer.json の scripts セクション
{
"scripts": {
"lint": "php -l app/ tests/",
"analyse": "./vendor/bin/phpstan analyse",
"format": "./vendor/bin/php-cs-fixer fix",
"test": "php artisan test",
"check": [
"@lint",
"@analyse",
"@test"
]
}
}
CLAUDE.mdに「コード変更後は composer check を実行すること」と記載しておけば、Claude Codeがコード変更のたびに自動で品質チェックを実行します。
8. PHP開発で使えるClaude Codeの実践Tips
ここまでの基本を踏まえた上で、日常のPHP開発で活用できる実践的なTipsを紹介します。
Tip 1: デバッグの効率化
エラーが発生した際、エラーメッセージとスタックトレースをClaude Codeに渡すだけで原因特定と修正を一気に行えます。
# Claude Codeへの指示
> 以下のエラーが発生しています。原因を特定して修正してください。
TypeError: App\Services\OrderService::calculateTotal():
Return value must be of type int,
null returned in /app/Services/OrderService.php:45
Tip 2: データベースマイグレーションの安全な作成
マイグレーションの作成時に「ダウン方法も含めて」と指示すると、ロールバック可能なマイグレーションを確実に作成します。
# Claude Codeへの指示
> usersテーブルにphone_numberカラムを追加する
マイグレーションを作成してください。
- nullable、unique制約付き
- down()メソッドも必ず実装
- 既存データへの影響を考慮
Tip 3: コードリファクタリング
Fat Controllerやロングメソッドの分割もClaude Codeが得意とするタスクです。
# Claude Codeへの指示
> app/Http/Controllers/OrderController.php の
storeメソッドが150行あります。
以下の方針でリファクタリングしてください。
- バリデーション → FormRequest
- ビジネスロジック → Service層
- DB操作 → Repository層
- コントローラは薄く保つ
- 既存テストが壊れないこと
Tip 4: MCP Serverを活用したPHP開発
Claude CodeのMCP(Model Context Protocol)Server機能を使えば、データベースへの直接接続やAPI連携も可能になります。
# MCP Serverの設定例(~/.claude/settings.json)
{
"mcpServers": {
"mysql": {
"command": "npx",
"args": [
"-y",
"@anthropic-ai/claude-code-mysql-mcp",
"--host", "localhost",
"--database", "my_app",
"--user", "root"
]
}
}
}
MCPサーバーの詳しい構築方法は「Claude Code MCP Server構築ガイド」を参照してください。
Tip 5: .claude/rulesで品質ルールを自動適用
プロジェクトの.claude/rules/ディレクトリにルールファイルを配置すると、Claude Codeが自動的に従います。
# .claude/rules/php-quality.md
## PHPコーディングルール
### 必須
- declare(strict_types=1) をすべてのPHPファイルに追加
- メソッドには戻り値の型宣言を必ず付ける
- SQLインジェクション対策: PDOプリペアドステートメント使用
### 禁止
- var_dump(), print_r() の使用禁止
- @(エラー抑制演算子)の使用禁止
- グローバル変数の使用禁止
### テスト
- コード変更時は関連テストも更新すること
- テストカバレッジ80%以上を維持
Tip 6: Git連携による安全な開発フロー
Claude Codeはgitコマンドを理解しているため、ブランチ作成からコミットまでを一連のフローで行えます。
# Claude Codeへの指示
> feature/payment ブランチを作成して、
Stripe決済機能を実装してください。
実装が完了したら、変更内容を要約した
コミットメッセージ付きでコミットしてください。
9. よくある質問(FAQ)
はい、PHP 7.4以降であれば問題なく使用できます。CLAUDE.mdにPHPバージョンを明記しておけば、Claude Codeがそのバージョンに適したコードを生成します。ただしPHP 8.0以降の方が型システムが充実しているため、より正確なコード生成が期待できます。PHP 7.3以前のプロジェクトでも基本的な操作は可能ですが、非推奨関数の扱いに注意が必要です。
はい、Symfony、CakePHP、CodeIgniter、Slim、Laravelなど主要なPHPフレームワークすべてに対応しています。CLAUDE.mdにフレームワーク名とバージョン、ディレクトリ構造、コーディング規約を記載しておくことで、フレームワーク固有の規約に沿ったコード生成が可能です。特にSymfonyはサービスコンテナやDoctrine ORMの構造を明記すると効果的です。
Claude Codeはプロジェクト内の既存テストファイルを読み取り、命名規則やディレクトリ構造を自動検出します。そのため、既存テストと同じパターンで新しいテストを追加します。ただし、同名のテストクラスやメソッドが存在する場合は上書きの確認が入ります。CLAUDE.mdにテスト規約を明記しておくとさらに安全です。
WordPressプラグイン開発では、WordPress Coding Standardsに準拠する必要があります。CLAUDE.mdにwpcs(WordPress Coding Standards)の使用を明記してください。また、セキュリティ面でnonce検証、データエスケープ(esc_html、esc_attr等)、権限チェック(current_user_can)の使用をルールとして定義することを推奨します。データベースアクセスにはwpdbのprepareメソッドを必須とする設定も効果的です。
PHPStan(レベル6以上推奨)とPHP CS Fixerをプロジェクトに導入し、CLAUDE.mdで「コード生成後に必ずphpstan analyseとphp-cs-fixer fixを実行すること」と記載してください。Claude Codeは指示に従い、コード生成後に自動で静的解析を実行し、エラーがあれば修正まで行います。さらにPHPUnitテストの実行も同時に指示すると、品質の三重チェックが実現できます。
はい、Claude Codeはcomposer requireやcomposer updateなどのコマンドを実行できます。「Stripeの決済機能を追加して」と指示すれば、composer require stripe/stripe-phpの実行からコードの実装まで一貫して行います。ただし、CLAUDE.mdで許可するComposer操作の範囲を明記しておくことを推奨します。本番環境では--no-devオプションの使用なども指定できます。
Claude Codeはターミナル上で動作するため、Dockerコンテナ内のPHPやXAMPPのPHPを直接実行できます。Docker環境の場合はdocker exec経由でのコマンド実行が可能です。CLAUDE.mdに「PHP実行はdocker exec app-container php で行うこと」と記載すれば、Claude Codeはその環境を使ってテストや構文チェックを実行します。Sail(Laravel用Docker)との相性も良好です。
まとめ
Claude CodeはPHP開発の全工程を強力にサポートします。この記事のポイントをまとめます。
- CLAUDE.mdが鍵 - PHPバージョン、フレームワーク、コーディング規約を明記することで生成コードの精度が飛躍的に向上
- PHPStan連携で型安全 - レベル6以上のPHPStanとClaude Codeを組み合わせることで、型安全なコードを自動生成
- テスト自動生成 - PHPUnitテストをClaude Codeに任せることで、テストカバレッジを効率的に向上
- Laravel・WordPress対応 - フレームワーク固有の規約を理解した高品質なコード生成
- Composer連携 - パッケージ管理からセキュリティアップデートまで自動化
まずはCLAUDE.mdの作成から始めて、PHPStanとPHPUnitを導入してみてください。Claude Codeがあなたの開発パートナーとして、日々のPHP開発を劇的に変えてくれるはずです。