php-database について
PHP開発者向けのデータベーススキルで、PDO、ORM、クエリ調整、スキーマ設計、マイグレーションを扱います。トピックとレベルに応じて学習内容を選べます。
主な機能
- 01PDOとプリペアドステートメント
- 02EloquentとDoctrineのORMパターン
- 03クエリ調整とインデックス
- 04スキーマとマイグレーションの指針
- 05トランザクションとリトライ処理
活用シーン
- 01PDOの接続とクエリの基礎学習
- 02EXPLAINによる低速クエリの調査
- 03遅延読み込み防止によるN+1対策
- 04リトライによるデータベースデッドロック対応
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ pluginagentmarketplace/ custom-plugin-php --skill php-databaseインストール後、Claude Code で/php-databaseを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
assets/config.yamlschema.jsonreferences/GUIDE.mdPATTERNS.mdscripts/validate.py詳細
PHP データベーススキル
PHP でのデータベース操作を習得するためのアトミックスキル
概要
PDO、ORM パターン、クエリ最適化、スキーマ設計、マイグレーションを網羅した、PHP でのデータベース操作に関する包括的なスキルです。
スキルパラメーター
入力検証
interface SkillParams {
topic:
| "pdo" // Native PHP database
| "eloquent" // Laravel ORM
| "doctrine" // Symfony ORM
| "optimization" // Query tuning, indexing
| "migrations" // Schema versioning
| "transactions"; // ACID, locking
level: "beginner" | "intermediate" | "advanced";
database?: "mysql" | "postgresql" | "sqlite";
orm?: "eloquent" | "doctrine" | "none";
}
検証ルール
validation:
topic:
required: true
allowed: [pdo, eloquent, doctrine, optimization, migrations, transactions]
level:
required: true
database:
default: "mysql"
学習モジュール
モジュール 1:PDO の基礎
beginner:
- Connection and DSN
- Prepared statements
- Fetching results
intermediate:
- Error handling modes
- Transactions basics
- Named placeholders
advanced:
- Connection pooling
- Stored procedures
- Batch operations
モジュール 2:クエリ最適化
beginner:
- Basic indexing
- EXPLAIN basics
- WHERE clause optimization
intermediate:
- Composite indexes
- Join optimization
- Query profiling
advanced:
- Execution plan analysis
- Partitioning
- Query caching
モジュール 3:ORM パターン
beginner:
- Model basics
- CRUD operations
- Simple relationships
intermediate:
- Eager loading (N+1 prevention)
- Query scopes
- Lifecycle hooks
advanced:
- Custom repositories
- Result caching
- Batch processing
エラー処理と再試行ロジック
errors:
CONNECTION_ERROR:
code: "DB_001"
recovery: "Check connection string, retry with backoff"
DEADLOCK_ERROR:
code: "DB_002"
recovery: "Retry transaction with exponential backoff"
QUERY_ERROR:
code: "DB_003"
recovery: "Check SQL syntax, validate parameters"
retry:
max_attempts: 3
backoff:
type: exponential
initial_delay_ms: 100
max_delay_ms: 2000
retryable: [CONNECTION_ERROR, DEADLOCK_ERROR]
コード例
プリペアドステートメントを使った PDO
<?php
declare(strict_types=1);
final class Database
{
private \PDO $pdo;
public function __construct(string $dsn, string $user, string $pass)
{
$this->pdo = new \PDO($dsn, $user, $pass, [
\PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION,
\PDO::ATTR_DEFAULT_FETCH_MODE => \PDO::FETCH_ASSOC,
\PDO::ATTR_EMULATE_PREPARES => false,
]);
}
public function findById(int $id): ?array
{
$stmt = $this->pdo->prepare('SELECT * FROM users WHERE id = :id');
$stmt->execute(['id' => $id]);
return $stmt->fetch() ?: null;
}
public function insert(array $data): int
{
$stmt = $this->pdo->prepare(
'INSERT INTO users (name, email) VALUES (:name, :email)'
);
$stmt->execute($data);
return (int) $this->pdo->lastInsertId();
}
}
再試行を伴うトランザクション
<?php
declare(strict_types=1);
final class TransactionService
{
public function executeWithRetry(
\PDO $pdo,
callable $operation,
int $maxRetries = 3
): mixed {
$attempt = 0;
while (true) {
try {
$pdo->beginTransaction();
$result = $operation($pdo);
$pdo->commit();
return $result;
} catch (\PDOException $e) {
$pdo->rollBack();
if (++$attempt >= $maxRetries || !$this->isRetryable($e)) {
throw $e;
}
usleep(100000 * pow(2, $attempt)); // Exponential backoff
}
}
}
private function isRetryable(\PDOException $e): bool
{
return str_contains($e->getMessage(), 'Deadlock');
}
}
N+1 の防止(Eloquent)
<?php
// BAD: N+1 problem
$posts = Post::all();
foreach ($posts as $post) {
echo $post->author->name; // Query per post!
}
// GOOD: Eager loading
$posts = Post::with('author')->get();
foreach ($posts as $post) {
echo $post->author->name; // No extra queries
}
// BETTER: Select specific columns
$posts = Post::with(['author:id,name'])->get(['id', 'title', 'author_id']);
クエリ最適化
-- Before: Full table scan
SELECT * FROM orders WHERE status = 'pending';
-- Step 1: Add index
CREATE INDEX idx_orders_status ON orders(status);
-- Step 2: Analyze with EXPLAIN
EXPLAIN SELECT * FROM orders WHERE status = 'pending';
-- Result: Index scan instead of full table scan
トラブルシューティング
| 問題 | 検出方法 | 解決策 |
|---|---|---|
| N+1 クエリ | Debugbar に 100 件以上のクエリが表示される | with() を使ったイーガーローディングを使用する |
| クエリが遅い | クエリが 1 秒を超える | インデックスを追加し、EXPLAIN を実行する |
| デッドロック | 「Deadlock found」エラー | 再試行ロジックを実装する |
| メモリ不足 | メモリ制限エラー | chunk() または cursor() を使用する |
メモリ効率の高い処理
<?php
// BAD: Loads all into memory
$users = User::all();
// GOOD: Chunk processing
User::chunk(1000, function ($users) {
foreach ($users as $user) {
// Process
}
});
// BETTER: Cursor for minimal memory
foreach (User::cursor() as $user) {
// Process one at a time
}
品質指標
| 指標 | 目標 |
|---|---|
| プリペアドステートメント | 100% |
| N+1 の防止 | 100% |
| インデックスの推奨 | ≥95% |
| トランザクションの安全性 | 100% |
使用方法
Skill("php-database", {topic: "optimization", level: "advanced"})
コメント
Markdown 対応