> > > PHPのORM比較: LaravelのORマッパー(Eloquent)の特徴

PHPのORM比較: LaravelのORマッパー(Eloquent)の特徴

2016-08-24 15:09 - NozawaTakeshi

最近とあるアプリケーションのライブラリを作成するプロジェクトがありまして、スクラッチで書いていたのですが、DB接続やSQLまわりが煩雑になり、やっぱりORMが欲しいなぁと探していたところ、今アツイと言われているPHPフレームワークの”Laravel”のORマッパーである”Eloquent”を見つけました。(こちらの記事で紹介されています)

フレームワークなのに、ORマッパーだけを独立して使うことができるようです。

今回はDoctrine、Idiorm&Paris、EloquentなどのPHP製のORMを比較し、Eloquentの特徴や使用感をご紹介したいと思います。

ORMの比較: Doctrine, Idiorm&Paris, Eloquent

Doctrine

ここで紹介されてもいる通り、DoctrineはPHPのORMのなかでは
スタンダード的な位置づけだとは思います。

ただ、以前Symfonyを使った時には、非常に難解だったのを記憶しています。
確かにものすごく高機能ではありますが、学習コストの高さと、
今回のプロジェクトの要件/サイズを考えると
もうちょっとシンプルで楽に使えるのが無いかを探してみました。

Idiorm

この記事でも紹介されている”Idiorm”も試してみたところ
とてもシンプルで使いやすいと思いましたが、開発が2014年以降止まっており、
作者の方も「バグフィックスなどのメンテナンスはしていくが、必要な機能は完成したのでもうこれ以上の機能追加はしない」と断言しておりました。

Feature complete
Idiorm is now considered to be feature complete as of version 1.5.0. Whilst it will continue to be maintained with bug fixes there will be no further new features added from this point on.

github公式ページのコメントより

なお、こちらの作者はIdiormをベースにしたActive Record型のORMである
Paris“もリリースしています。
こちらも非常にシンプルで扱いやすいと思いますが、
Idiorm同様、新たな機能を追加する予定は無いようです。

今回の案件はサイズとしてはそこまで大きくはないですが
長期間使っていくものではあったので、
開発が活発に行われていることも重要だと判断し、採用を見送りました。

ですが、本当にシンプルなORMが欲しければ(MySQLだけに限られますが)、
Idiorm&Parisは十分だと思います。

Eloquent

さて、さきほど紹介した記事によるとEloquent

The Eloquent ORM included with Laravel provides a beautiful, simple ActiveRecord implementation for working with your database.

なのだそうです。
Doctrineよりも学習しやすいとあります。

実際使い始めてみると、比較的シンプルかなという感じです。
ただし、処理するオブジェクトの数が多いので、
スタックトレースを見ると、結構な量になります。
もしかしたらやや重めなのかもしれませんが、
実際、本番環境で運用してみてはいますが、そこまで重さは感じません。

なお、クラスの数は多いもののの、適切にカプセル化されているので、
気にすべきクラスは2・3個くらいではあります。また、この記事には

It losses inherited advantages when used outside Laravel

とありますが、私はそうは思いません。

そもそもLaravel自体がORMやクエリビルダー、テンプレートなど
必要なパッケージをコンテナとして組み込むフレームワークなので、
ORMだけ欲しければEloquentを使えばいいし、
失うであろうLaravelの利便性が欲しければLaravelを使えば済む話です。

Laravelほど充実してなくていいから、もうちょっと軽量なものが欲しければ
Lumenという手もあります(LumenはLaravelの軽量フレームワークです)。

なおEloquentはphp5.6以上でないと動きませんのでご注意を。

Eloquentの特徴

公式ドキュメントのなかから特徴的だなと思うことをいくつかピックアップします。

・1テーブルに対して1エンティティモデルクラスです。
ここにCRUDの各メソッドを実装します。

・ネームスペース前提です。
あまり触れたことの無い方はチャンスだと思ってきちんと使いましょう。

・命名規則
テーブル名には命名規則はありません。
自分で、対応するテーブルの名前をプロパティにセットするだけです。

主キーやリレーションをとるテーブルの外部キーなどには
命名規則はありますが、自分で指定もできます。
このへんは柔軟性があります。

・timestamp
DATETIMEやint型のカラムに対してinsert時やupdated時に自動的に
タイムスタンプの更新をしてくれます。
もちろんオフにすることもできます。

・リレーション
一般的な一対一、一対多、多対多は問題なく実装できます。
CakePHPのようにプロパティでリレーションを設定するのではなく、
専用のメソッドのなかで定義をします。
なので、必要がない限りリレーションはされないようになっているようです。

・プロパティへのアクセス
エンティティモデルにはattributesというプロパティがあり、
setやgetとするとそのなかの配列要素にアクセスします。

例えばtitleというカラムがテーブルにあった場合、
検索結果のエンティティモデルにはSomeModel::$attribets[‘title’]に
実際のデータがセットされます。
(SomeModel::$titleにはなりません)。

このへんがちょっと分かりにくいポイントかもしれません。
マジックメソッドやマジックプロパティを多用している印象です。

検索クエリと検索結果

検索クエリの生成と検索結果に対する取り扱いがEloquentのなかでも特徴的な要素だと思います。

ですが、検索クエリを生成するのは一般的なORMとそこまで変わらないと思います。
SampleModel::where(‘status’,’1′)のようにwhere句を作ったりorderやlimitなどを指定できます。

これらのメソッドは全てクエリオブジェクトを返すので、
メソッドチェーンで書くことができます。

主キーを指定して検索しない場合のSELECTの結果は全て”Collection”というイテレーティブな配列オブジェクトになって返ってきます。

その配列オブジェクトでは、簡単に操作ができるメソッドが提供されています。
(結果の行数のカウントやさらなるフィルタリング、ORDERや、配列のある要素だけを抜き出して別の配列を作るなど)。

この機能自体はそこまで特殊なものではありませんが、
EloquentではこのCollectionクラスを継承して
独自のCollectionクラスを生成させるようにすることができます。
このことによってより柔軟に独自のメソッドを実装することができます。

また、クエリオブジェクトと結果の配列オブジェクトは
同名のメソッドが多く、結果に対する操作なのか、クエリに対する操作なのかを
気にせずプログラムを書いていくことができます。

共通のインタフェースは実装していないようには見えますが、
それを意図して作られていると思います(間違っているかもしれませんが)。

例えば、count()は
・クエリオブジェクト(Builder)の場合はSELECT COUNT()が実行され、該当の行数を返します。

・結果オブジェクト(Collection)の場合は返ってきた結果の配列の要素の数を数えて返します。

さらに言えば、Collectionはただの配列オブジェクトなので、検索結果のときだけに使うのでなくいつでも自由に呼び出すことができます。

どれも数を数えて返すという機能は同じですが、
命令するオブジェクトによって詳細は異なります。

いかにもオブジェクト指向な作りだと思いました。
他にもwhere()やorderBy()、take()、sum()など共通のメソッドがあります。

Lazy Load, Eager Load

Eloquentは両方をサポートしています。
Lazy Loadはリレーションを指定しなくても
検索結果オブジェクトに対してリレーショナルなオブジェクトに
アクセスした場合に、SELECT文が実行され、
必要なオブジェクトが生成され、アクセスすることができます。

利点はリレーションがあるのか、無いのかを気にせず
プログラムが書けて、さらに必要がないときには
リレーショナルなSQLを実行しない点です。

逆に必要なときには必ずSELECT文が実行されるので
取得する行数が多い場合などはパフォーマンスがよくありません。

そういった場合はEagerLoadingを有効にすることで
事前にリレーショナルなデータを取得しておくこともできます。
EagerLoadingはメソッドとして提供されており、
必要なときに呼び出すことができます。

Eloquentで特徴的なのはこのあたりでしょうか。

次回はEloquent単体をORMライブラリとして利用するやり方についてご紹介したいと思います。