はじめに
Symfony Advenet Calander 2016の21日目の記事です。
symfonyについてのちょっとしたHow Toものです。開発しているときに、ちょっとしたことですが「こういうことがやりたい」と思ったことがあって、そのときに編み出した小技です。逆引き集といえるほどでもないですが、ノウハウの共有や別のやり方のもとになれればと思います。
Profiler
symfonyのprofilerは便利で、かなりの情報がここから得られます。まだ使いきれていないですが、自分の経験で役に立ったと思うものをピックアップします。
使用されているテンプレート
profiler画面のtwigより、使用されているtwigテンプレートやどういう順番でレンダリングがされているかが一覧できます。どんなテンプレートを呼び出しているのか、何回繰り返されているのか、レンダリングかかる時間を確認したいときに便利です。
表示されるまでのタイムライン
profiler画面のtimelineより、リクエストから画面返却までのタイムラインが表示されます。
画面表示が遅いとき、どこで時間がかかっているかの大枠をおさえることができます。例えば、controller内の処理とテンプレートでのレンダリングのどっちに時間がかかっているかくらいであれば、この機能で十分測定できます。
実行されたクエリ(doctrineを使っている場合のみ)
profilerのdoctrineより、その画面で使用されたSQLの情報が表示されます。
prepared sql文に渡されたパラメタ、実際に実行されたSQL文、explainなども見れるので至れり尽くせりです。
dumpによるデバッグ
書こうと思ったら、すでに去年の記事 にありました...
いわゆる、プリントデバッグの延長にあるテクニックですが、
ポイントは、
- profilerからすぐに確認できる
- var_dump()はもういらない
- twigでも使える
です。controllerで、意図した分岐に入っているか、想定どおりの値かを確認するのによく使っています。
マッチしたルーティングの確認
profilerのroutingより、どのルーティングにマッチしたかどうかが確認できます。
ルーティングに正規表現やドメイン制限してる場合は、この画面で想定どおりの動きかを確認するのに役立ちます。
ルーティング
ホスト名での制限
URLのルールは同じだけど、サブドメインによって処理を分けたいとき
@Route("/test/{pageNumber}", host="dev1.example.com")
@Route("/test/{pageNumber}", host="dev2.example.com")
パスパラメタにプレフィックス・サフィックスをもたせる
ページ数などをパスパラメタに持たせたとき、ページ数とわかるように、「page-」などをつけたいとき
@Route("/sample/page-{number}")
@Route("/sample/{number}-page")
種類などを表すパラメタで、値の数が限られているとき
例えば、(グルメ、旅行、買い物)のようなサイト内で決め打ちのカテゴリがあって、それらのトップページを共通のアクションで実現したいとき
@Route("/top/{category}", requirements={"category"="(gourmet|travel|shopping)"})
パターンが少ないときは正規表現を使うと手軽でわかりやすい
コンソールコマンド
標準エラーに出力
protected function execute(InputInterface $input, OutputInterface $output)
{
$std = $output instanceof ConsoleOutputInterface ? $output->getErrorOutput() : $output;
$std->writeln('<error>error message</error>');
}
メッセージの装飾
<info></info>
などでくくると、標準出力での表示がちょっとキレイになります。
詳細は本家のページをどうぞ。
https://symfony.com/doc/current/console/coloring.html
その他
キャッシュクリアは「--no-warmup」をつける
こちらの記事 を参考にしました。
ロード時に、リクエストのドメインや、実行環境のホスト名などをみて、定数を決める場合、キャッシュを自動生成させると、思わぬ事故が発生します。時間短縮の観点からもウォームアップなしの方が安全のようです。
php app/console cache:clear --no-warmup
SingletonをDI機能で導入
インスタンスをひとつだけ作ってそれを使い続けたい場合。実はデフォルトで、symfonyのサービスコンテナーは、同じインスタンスを提供しつづける仕様になっています。クラスの方でSingletonとして設計するのもありですが、面倒ならサービスコンテナから提供させるという選択肢もあるということです。
As a bonus, the Mailer service is only created once and the same instance is
returned each time you ask for the service. This is almost always the behavior
you'll need (it's more flexible and powerful), but you'll learn later how you can
configure a service that has multiple instances in the How to Define Non Shared
Services article.
例えば、DBに接続するためのインスタンスは、コネクション数を抑制したいなどから、ひとつのインスタンスにしたくなります。そういう場合は下記のようなクラスを作成して、これをDIから提供させればOKです。DIを使っていると、テスト時はテスト用のクラスにするなどの使い分けできるので、Singletonとしてclass作成するより柔軟に使えます。こちらの記事でも、そういった示唆があり、参考にさせていただきました。
class DBSingleton {
private $DBConnection;
public function __construct() {...}
}
ちなみに、2.8から、逆に毎回新しいインスタンスを提供させることもできます。このページでもデフォルトでは一度作成したインスタンスを使い続けるとあります。
http://symfony.com/doc/2.8/service_container/shared.html
In the service container, all services are shared by default.
This means that each time you retrieve the service, you'll get the same instance.
singletonについての参考サイト
- https://ja.wikipedia.org/wiki/Singleton_%E3%83%91%E3%82%BF%E3%83%BC%E3%83%B3
- シングルトンのベターな実装方法
- http://hiroaki-kono.hatenablog.com/entry/2014/05/04/135130
- Singleton何が悪いの?
- Singleton パターンの使いどころをまとめてみた
参考サイト
- http://kseta.hatenablog.jp/entry/2014/12/02/004208
- http://shiro-goma.hatenablog.com/entry/2014/12/19/114144
- http://tdak.hateblo.jp/entry/20141213/1418462893
- http://okapon-pon.hatenablog.com/entry/symfony-debug
- http://qiita.com/tarokamikaze/items/b6cb73be0294fe6b14c1
- http://d.hatena.ne.jp/jiskay/20110606/1307332702
- http://tech.quartetcom.co.jp/2015/12/11/easyadminbundle/
- http://symnote.kwalk.jp/public/debug
- https://gist.github.com/MattKetmo/3665488
- https://symfony.com/blog/new-in-symfony-2-4-show-logs-in-console
- https://symfony.com/doc/current/console/coloring.html