株式会社クイックのWebサービス開発blog

HAPPYなエンジニア&デザイナーのブログです

FuelPHPでRailsのpry-railsみたいなことする

PHP再入門中の五所です。

FuelPHPRailsのpry-railsみたいなことをしようとして、それなりに(半日)はまりましたー。

もうvar_dump($hoge);exit;みたいなことをちまちまやりたくないですからね。

PHPでREPL使いたい

Psy ShellというRubyのPryやPythonのIPython並のデバッグ力を持つライブラリがあるので、それを使います。

Composerで追加しておいてください。

Composerをまだ使っていない方は、ぜひ下記をご覧ください。

aimstogeek.hatenablog.com

REPL: コマンドラインから1行ずつコマンドを実行できるツール。 スクリプトの実行をやめて、インタラクティブデバッグできる機能(デバッガ)が付属していることが多い。これ超便利。

Railsのbinding.pryみたいなことがしたい

Railsのbinding.pryは、アプリケーションサーバの実行を中断してデバッグできる便利機能です。

詳細は下記をご覧ください。

railstutorial.jp

これをFuelPHPで再現していきます。

上で紹介したPsy Shellは、ソースコード中にeval(\Psy\Sh());とすれば実行を中断してデバッグする機能がありますので、これを利用すればできそうです。

そのためには、ApacheではなくPHP 5.4から追加されたビルトインサーバ機能でPHPを動作させる必要があります。

が、下記で糾弾されているように、ビルトインサーバは機能が不十分です。

PHP :: Bug #61286 :: If the trailing path that follows a script contains a dot PATH_INFO is not set

拡張子のついたURLをルーティングできない

PHPのビルトインサーバ(以下、PHPサーバ)は、拡張子のついたURLをすべて静的ファイルとみなし、かつサーバ変数$_SERVER['PATH_INFO']をセットしてくれません。

普段ならApacheがセットしてくれるので、何も問題は起きないのですが・・・。

FuelPHPはまず$_SERVER['PATH_INFO']を見てルーティングしているので、この変数がセットされていないとFuelPHPは静的なファイルを返します。

たとえば、FuelPHPのREST_Controllerを使おうとすると、URLは

http://localhost:3000/user/1.json

みたいになると思いますが、これが404エラーを吐きます。

そこで、

  • JSONファイルの場合、$_SERVER['PATH_INFO']に拡張子を消したリクエストURIをセット

という処理をFuelPHPに渡す前に噛ませることで、無理矢理ルーティングさせます。

ついでに

  • FUEL_ENVをセット
  • 静的ファイルの場合、処理を中断してファイルを返す

という処理も噛ませちゃいます。

/パス/to/public/router.php

<?php

// define environment
$_SERVER["FUEL_ENV"] = 'development';

// static files
if (preg_match('/\.(?:png|jpg|jpeg|gif|css|js).?[0-9]{0,10}$/',
               $_SERVER["REQUEST_URI"])
    or strpos($_SERVER["REQUEST_URI"], 'assets/fonts'))
{
    return false;
}

// requests including '.json'
if (strpos($_SERVER['REQUEST_URI'], '.json'))
{
    $_SERVER["PATH_INFO"] = preg_replace('/\?.+$/', '',
                                          $_SERVER['REQUEST_URI']);
}

require_once __DIR__.'/index.php';

ビルトインサーバの起動時に、このファイルをエントリポイントに指定します。

cd /path/to/public
php -S 0.0.0.0:3000 router.php

ビルトインサーバで稼働できれば、好きなところで

eval(Psy\Sh());

ってやれば、インタラクティブデバッガが起動できますね!!

試しに起動時に何ができるか見てみます。

[k-gosho@localhost] % php -S 0.0.0.0:3000 router.php
PHP 5.5.15 Development Server started at Fri Jul 22 09:26:34 2016
Listening on http://0.0.0.0:3000
Document root is /var/www/public
Press Ctrl-C to quit.
[Fri Jul 22 09:26:36 2016] 172.16.XX.XXX:55234 [200]: /assets/css/style.css?1467956972
[Fri Jul 22 09:26:36 2016] 172.16.XX.XXX:55238 [200]: /assets/js/common.js?1468500094

(~~ 中略 ~~)

[Fri Jul 22 09:26:44 2016] 172.16.XX.XXX:55334 [200]: /assets/fonts/fontawesome-webfont.woff?v=4.0.3

(~~ ここで、ソースコード中にeval(Psy\Sh());を挿入してアクセス ~~)

Psy Shell v0.7.2 (PHP 5.5.15 — cli-server) by Justin Hileman
>>> $_POST
=> [
     "user" => "456",
     "team" => "",
     "apply" => "3",
     "status" => "1",
   ]
>>> $_SERVER
=> [
     "DOCUMENT_ROOT" => "/var/www/public",
     "REMOTE_ADDR" => "172.16.XX.XXX",
     "REMOTE_PORT" => "55370",
     "SERVER_SOFTWARE" => "PHP 5.5.15 Development Server",
     "SERVER_PROTOCOL" => "HTTP/1.1",
     "SERVER_NAME" => "0.0.0.0",
     "SERVER_PORT" => "3000",
     "REQUEST_URI" => "/progress",
     "REQUEST_METHOD" => "POST",
     "SCRIPT_NAME" => "/index.php",
     "SCRIPT_FILENAME" => "/var/www/public/index.php",
     "PATH_INFO" => "/progress",
     "PHP_SELF" => "/index.php/progress",
     "HTTP_HOST" => "localhost:3000",
     "HTTP_CONNECTION" => "keep-alive",
     "HTTP_CONTENT_LENGTH" => "65",
     "HTTP_CACHE_CONTROL" => "max-age=0",
     "HTTP_ORIGIN" => "http://localhost:3000",
     "HTTP_UPGRADE_INSECURE_REQUESTS" => "1",
     "HTTP_USER_AGENT" => "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Ubuntu Chromium/51.0.2704.79 Chrome/51.0.2704.79 Safari/537.36",
     "HTTP_CONTENT_TYPE" => "application/x-www-form-urlencoded",
     "HTTP_ACCEPT" => "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8",
     "HTTP_REFERER" => "http://localhost:3000/",
     "HTTP_ACCEPT_ENCODING" => "gzip, deflate",
     "HTTP_ACCEPT_LANGUAGE" => "en-US,en;q=0.8,ja;q=0.6",
     "HTTP_COOKIE" => "fuelmid=mEflV......HOckpWr",
     "REQUEST_TIME_FLOAT" => 1469147215.662,
     "REQUEST_TIME" => 1469147215,
   ]
>>>

こんな感じで、PHPサーバの実行をやめて、$_POST$_SERVERを確認できました!

もちろん、定義されているすべての変数・クラス・オブジェクトが確認できます。

更にその場でメソッドも実行できるので、デバッグが捗りますね。

変数・メソッド名をタブ補完できるのも楽!

ちなみに、Laravelの場合は、php artisan serveコマンドが最初からあるので、この手順は必要ありません。Laravelいいなー

rails consoleみたいなことがしたい

FuelPHPは、標準のphp oil consoleが不便すぎるので、これもPsy Shellにしちゃいましょう。 下記コマンドでphp oil consoleを凌ぐ強力なコンソールが起動できます。

FUEL_ENV=development psysh /path/to/public/index.php

Psy Shell v0.7.2 (PHP 5.5.15 — cli) by Justin Hileman
HttpNotFoundException with message ''

>>>

せっかく立ち上げたので、モデルを生成してみましょう。仮想的なModel_Userクラスを作ります。

User belongs_to Team な関係を想定します)

>>> $user = Model_User::find(1)
=> Model_User {#207}

>>> $user->id
=> "1"

>>> $user->name
=> "Jon"

>>> $user->team_id
=> "1"

>>> $user->team->name
=> "Web service development division"

これでRuby on Railsに負けない開発環境ができましたね!!

ちなみに、Laravelの場合は、php artisan tinkerコマンドが最初からあるので、この手順は必要ありません。Laravelいいなー

おまけ

テストの自動生成? Asset Pipeline?

Laravelならできるのかも。Fuelは無理。