Weaver ORM とは?
Weaver ORM は、Symfony アプリケーション向けの PHP 8.4 以上対応のオブジェクト関係マッパー(ORM)です。単一の原則に基づいて構築されています:ドメインオブジェクトはデータベースについて一切知識を持つべきではない。エンティティクラスへのアノテーション不要、プロキシ生成不要、実行時リフレクション不要 — 純粋な PHP オブジェクトと、それらを SQL に変換する明示的なマッパークラスだけで構成されています。
Weaver が解決する問題
Doctrine のプロキシオブジェクト
Doctrine はすべての関連エンティティをプロキシクラスでラップし、プロパティへのアクセスを傍受して初回アクセス時に SQL クエリを実行します。従来のリクエスト/レスポンスサイクルでは見えませんが、N+1 クエリパターンを暗黙的に引き起こし、デバッグを困難にします(var_dump($post->getAuthor()) はユーザーではなくプロキシを出力します)。
長期稼働する PHP ワーカー(RoadRunner、FrankenPHP、Swoole、Symfony Messenger)では、EntityManager がリクエスト間で古い状態を蓄積し、リクエスト境界ごとに手動でリセットする必要があります — これは見逃しやすく、診断が難しいバグを引き起こします。
リフレクションベースのハイドレーション
Doctrine は ReflectionProperty を使用してエンティティオブジェクトのプラ イベート/プロテクトプロパティを直接設定し、ドメインロジックを迂回します。リクエストごとに PHP アトリビュートを再パースするか、ウォームキャッシュを参照する必要があり、プロキシクラスはディスク上に存在しなければなりません。
無制限のアイデンティティマップ
Doctrine の EntityManager はリクエストの間、ロードしたすべてのエンティティをメモリに保持します。大量の結果セットをロードすると、メモリが際限なく増大します。回避策である $em->clear() は、再永続化し忘れたエンティティも含め、すべてをデタッチしてしまいます。
Weaver の違い
Weaver は4つの原則に基づいて構築されています:
-
エンティティとしての純粋な PHP オブジェクト。
Userクラスは ORM への依存をゼロにします。アトリビュート不要、基底クラス不要、インターフェース不要。Symfony を起動したりデータベースに接続したりすることなくユニットテスト可能な、純粋な値オブジェクトまたはドメインオブジェクトです。 -
明示的なマッパークラス。 独立した
UserMapperクラスが、Userをusersテーブルにどのようにマップするかを記述します。カラム型、リレーション、プライマリキー — すべて一か所に、すべて純粋な PHP で、完全に grep 可能で静的解析可能です。 -
プロキシなし、暗黙的な遅延ロードなし。 リレーションは常に
->with(['relation'])を通じて明示的にロードされます。どの SQL がいつ実行されるかを常に把握できます。 -
ワーカーセーフな設計。 マッパーはステートレスで、ワーカープロセスごとに一度ロードされます。各 HTTP リクエストまたは Messenger ジョブは独自の
EntityWorkspace(作業単位)を持つため、リクエスト間での共有ミュータブル状態はありません。
主要な差別化ポイント
| 機能 | Doctrine ORM | Weaver ORM |
|---|---|---|
| プロキシクラスの生成 | 必要 | 不要 |
| 実行時リフレクション | あり | なし |
| 遅延ロード | 暗黙的(プロキシ) | 明示的のみ |
| エンティティアノテーション/アトリビュート | エンティティクラス上 | 独立したマッパークラス |
| リセット時のワーカープロセス再起動 | 必要 | 不要 |
| N+1 防止 | 手動 JOIN FETCH | with() によって強制 |
| 10k 行あたりのメモリ | 〜48 MB | 〜11 MB |
| 10k 行のハイドレーション時間 | 〜420 ms | 〜95 ms |
| PHPStan /静的解析 | 部分的(マジックプロキシ) | 完全(明示的マッパー) |
ベンチマーク:PHP 8.4、PostgreSQL 16、Ubuntu 22.04、
Profileリレーションを持つ 10,000 件のUser行。結果はハードウェアとクエリの複雑さによって異なります。
アーキテクチャの概要
エンティティ(純粋な PHP クラス — ORM への結合ゼロ)
│
└── マッパー(テーブル名、カラム、リレーション、hydrate/extract)
│
└── EntityWorkspace → QueryBuilder → PDO/DBAL
EntityWorkspace は Doctrine の EntityManager を置き換えます。これはリクエストスコープの作業単位で、flush() が呼ばれたときにどのエンティティを挿入、更新、または削除する必要があるかを追跡します。リクエストスコープであるため、リクエスト間でアイデンティティマップがリークすることはありません。
PyroSQL サポート
Weaver は PyroSQL(高性能なインプロセス分析 SQL エンジン)のオプションサポートを提供しています。PyroSQL は、プライマリリレーショナルデータベースに触れることなく、集計クエリ、レポーティング、大規模データセット操作のためのリードレプリカとして使用できます。詳細は PyroSQL セクション を参照してください。
要件
| 依存関係 | 最小バージョン |
|---|---|
| PHP | 8.4 |
| Symfony | 7.0 |
| doctrine/dbal | 4.0(接続レイヤーのみ) |
| MySQL | 8.0 |
| PostgreSQL | 14 |
| SQLite | 3.35 |
オプション:
symfony/messenger— 非同期イベントパブリッシュとアウトボックスパターンsymfony/cache— クエリ結果キャッシングmongodb/mongodb+ext-mongodb— MongoDB ドキュメントマッパーサポート
Weaver でないもの
Weaver は Doctrine のドロップイン代替品ではありません。Doctrine の DQL、クライテリア API、またはアトリビュートベースのマイグレーションに強く依存している場合、そのレイヤーを書き直す必要があります。Weaver はグリーンフィールドの Symfony 7 以上プロジェクトや、明示的で予測可能な SQL とワーカーセーフな永続化を求めて Doctrine から移行中のアプリケーションに最適です。