nazolabo

なぞさんのブログ

Laravel5を業務で一通り使ってみた感想

2ヶ月くらい使ってみたけど、悪くはないんだけど、なんか最近持ち上げられすぎてる気がするので、気になったところを書き出してみる。

あくまで個人的な感想なので、マサカリ投げるのは歓迎。

概要

Noticeを含むエラーが全て例外になる

最近のフレームワークは大体やってそうだけど、エラーを出すと全て例外を出すので、不要にcatchしなければ問答無用で落ちる。これにより、NOTICE出しっぱなしで何となく動いているコードを殲滅できる。標準にしてほしい。Fatalも例外として扱ってくれるが、Fatalを取れるのはプログラム終了後なので、特に意味はない。出力が同一フォーマットになるくらい。

ちなみに自前で実装するにはErrorExceptionのページに書いてあるので、この通り実装しよう。簡単である。

ファイルの配置が自由

composer autoload使っていればどれでもそうなんだけど、ModelとかServiceとか別に規定のフォルダに配置する必要はない。namespaceさえ解決できればどこからでも読み込める。これにより、アプリを複数に分けたいけどModelは共有したい、というような配置も簡単にできる。自分は本体と管理画面を別アプリにしつつ、Modelと、ビジネスロジック(いわゆるDDDにおけるサービス)は同一のディレクトリから参照している。

具体的には、composer.jsonに以下のように書き足せば良い。

    "autoload": {
        "psr-4": {
            "App\\": "app/",
            "Model\\": "../models/"
        },

psr-4と書いてある通り、ここに記載したものは、PSR-4に準拠した形式でautoloadされる。簡単に言えば、jsonに記載したパスを起点として、namespaceの区切りとディレクトリ構造が一致している前提で読み込みに行く。今時autoload周りは自分で書くことはない。

Laravelはディレクトリの規定がほとんど無く、namespaceからautoloadできれば何をどこに置いても大体動くので、うまく使おう。

なぜかソースフォーマットがPSR-2無視

タブインデントしたり改行位置が独特だったり謎が多い。自動生成した時とかにイラッと来る。何で無視しているのかよくわからないが、とりあえずしばらくはこのままらしい

そもそもSymfony Component使いまくり

これのせいで、たまにソースを追うと、コアを読んでるはずなのに突然vendor/symfony以下に移動しないといけなくなってだるい(Requestとか)。それって結局Symfony系でいいのでは…?一方で、何でもフルスクラッチすればいいってものではないというのもわかる。

DIが強い

ControllerにDIし放題(後述のリフレクション)とか、FacadeとかContractの仕組みによってDIが簡単になっている。と思う。ナチュラルに使うのであまり意識することはない。ナチュラルに使えるくらい良く出来ているのではないかと思う。押し付け感は少ない。

ルーティング

prefixやドメイン名でグルーピングできたり、ルーティングでMiddlewareを足したりできるのでかなり優秀。LaravelCollectiveを使えばannotationで指定もできる。自分は使っていない。

Middlewareというのはいわゆるフィルタ的な、共通の事前処理のようなもの。認証チェックとかビューの共通変数を当てたりするのに使うことが多い。

リフレクション

例えば、Controllerのコンストラクタに、勝手に引数を追加したりすると、そのインスタンスが何故か勝手に渡ってくる。以下はドキュメントから引用

<?php namespace App\Http\Controllers;

use Illuminate\Routing\Controller;
use App\Repositories\UserRepository;

class UserController extends Controller {

    /**
     * The user repository instance.
     */
    protected $users;

    /**
     * Create a new controller instance.
     *
     * @param  UserRepository  $users
     * @return void
     */
    public function __construct(UserRepository $users)
    {
        $this->users = $users;
    }

}

この例では、コントローラーのコンストラクタに突然UserRepositoryが登場するが、実行するとちゃんとインスタンスが渡ってくる。例えばCakePHPだと、プロパティにprotected $uses = ['User'];のように、規定されたものを規定された通りに読み込むことしかできないが、このパターンであれば何でも注入することができる。

まあこれだけだと、普通にnewすればいいじゃん、とも思うが、Contractsと組み合わせると、Controllerに渡すのは定義だけで、実装を何にするかは別の場所で定義することができる。強い。

難点としては、リフレクション使いまくりなので、多分処理速度がかなり犠牲になっているのでは、と思う。ベンチマークはしていない。

Eloquent(O/Rマッパー)

Laravel標準のO/RマッパーであるEloquentだが、何故か今時ActiveRecordっぽい感じだったり、複合PKが扱えなかったり(ちょっと改造すると扱えるようになるが)と、時代遅れ感が強い。CakePHPですら3.0になってテーブルとエンティティを分離している

クエリビルダ自体はそこそこ優秀で、行ロックやバルクインサート、JOIN周りもちゃんと書けるので、実用的ではあるのだが、今時ならDataMapperを採用していただきたかったところ。フォローしておくと、Eloquent自体も、HasMany的なものは明示指定しない限り呼び出されない(余計なことをしない&自動Memoizeしてくれる)とか、Collectionが楽とか、いいところもある。

自分はあまり考えずに導入してしまい後戻りができなくなっているが、新規に書くのであれば、O/RマッパーだけDoctrineを使うことも十分に検討したほうがいいと思う。ただし認証周りなどのDBに依存する標準機能が全滅するので、そこはちょっと面倒。まあ認証あまり使ってないけど。

MigrationやSeeding(いわゆるfixture的なやつ)もあるけど、特にモデルと連動していないし、phpmigとかでいいんじゃないかなとも思う。Eloquent含めて全部セットで使うには便利だし、特に避ける理由はない。

認証

標準で認証周りが用意されているが、正直めんどくさい。

拡張性も十分に用意されているのだが、ドキュメントが少なく、結局ソースを読んでいるうちに最初からスクラッチで書けば済むのでは…という感じになる。ソースコード自体を再配布するようなものでなければ、標準のものは無視してスクラッチで書いてしまえばいいと思う。いずれにせよ、認証周りのソースコードAuthManagerGuardRegistrarあたり)は読んでおく必要がある。

Middleware+DIが優秀なので、自分で書くにもそんなに苦労はしないと思う。

Blade(テンプレートエンジン)

悪くないんだけど微妙。Twigに対するアドバンテージが特に思いつかない。せめてプラグイン的なものは用意してほしかったような…。テンプレート継承とかは用意されているし、PHP解釈できるから最小限のもの以外はPHPで書けばいいじゃんってのはわかるんだけど…。うーん…。

あとフォームヘルパはLaravelCollectiveに置いてある。そのままだとさすがにdefaultとかの処理が面倒なので使おう。

テンプレートの機能ではないが、old('name')と書くと、前回のフォーム入力情報を取得できるのは便利。入力失敗した時とかにわざわざController側で同じ入力値をViewに渡す必要がない。<input type="text" name="name" value="{{ old('name', $user->name) }}" />のように書くことが多い。(oldの第二引数はデフォルト値)

Storage

S3と通常のファイルシステムを同じように扱うことができる。これにより本番はS3、開発環境はファイルシステムということが簡単に書ける。便利。特定のファイルシステムの時だけの処理とかも書けるし、特に不満はない。

Laravel Elixir

gulpのラッパーだが、特にgulpのラッパーというもの以上の何かはない。素のgulpに比べて書きやすくはなっているが、複雑なことをしようとすると途端に面倒になるし、独自知識を覚えてもあまりメリットがないので、Laravelと心中するつもりでなければ、素直に素のgulpなり一般的なものを利用したほうがいい。JavaScriptなのでそもそもLaravelである必要も疑問。

同様の謎ラッパーにEnvoy(Ansible的なやつ)等もあるが、やはりAnsible使えよって思う。ってかLaravelCollectiveにも似たようなものがあるんですがそれは…。強いて言えば、Laravel Elixirと違い、こちらはPHPなので、なんでもPHPで書きたい!という人にはいいと思う。

キュー&タスクランナー

Envoyのほうじゃなくて、アプリ内タスクを動かすタスクランナー、つまりcron的なものが用意されている。いやcronで呼び出してはいるんだけどPHPはマルチスレッド系は絶望的なので、cronでスケジューリングしたりタスクキューを作ったりすることが多いが、これがPHP側で管理する方法が標準搭載されているのは良いと思う。と言ったものの、まだ使っていないので何とも言えない。実行プロセス数の制限とかどうするんだろう。

Homestead

Laravelがいきなり動くVagrant一式だが、何故かコマンドがPHPで書かれてて謎の努力を感じる。VagrantやHHVMの使用例として参考にする程度にはいいが、結局環境によって細かい変更するだろうし、自分で構築したほうがいいとは思う。ハンズオンとかで使うには便利だと思う。「Homestead入れておいてね」で済む。

テスト

まあ普通に書ける。URLにアクセスしてレスポンスを調べるようなテストも何も考えずに書ける。Migration+SeedingでDBが絡むテストも簡単に書ける。特に問題ない。

Dotenv

Laravelあまり関係ないけど、Laravelでは.envというファイルに設定を書く。これはphpdotenvの機能で、名前の通り、環境変数に相当するものを書くだけなので、環境変数として設定できるのであれば、どこからでも設定できる。例えばAWSのアクセスキーを最初から環境変数に入れている場合、改めて設定を書く必要がない。まあAWSの設定はaws-sdkが勝手に拾ってくれるけど…。

また、dotenvのような設定形式は他言語でもあるため(例えばgolangとか)、設定の共有が簡単に行うことができる。例えば、PHPでは苦手となる生socketを扱ってリアルタイム通信するような別プログラムと、メインのPHPアプリで、同じ設定ファイルを読む、といったことが可能になる。

Carbon

またLaravel関係ないが、Carbonに標準対応しているので、DBの日付設定とかが楽。

まとめ

個人的にはSilexでいいんじゃないかと思うことが多いが、まあこれはこれでいいんじゃないかなーと思う。よく検討してから使おう。でも好きなものがあるなら好きなものを使うのが一番だと思う。

Laravel関係ない内容が多いな…。