Home

Shin x blog

PhpStorm から Vagrant VM の PHP アプリケーションをリモートデバッグする(Web & CLI)

この記事の所要時間: 1011

logo_phpstorm

PhpStorm から Vagrant で構築した VM の PHP アプリケーションをリモートデバッグする方法です。Web アプリケーションだけでなく、CLI アプリケーションでもリモートデバッグできるように設定していきます。

VM スペック

  • 192.168.33.41 を private network で設定
  • PHP + Xdebug がインストール済み
  • ホストと VM は、synced folder でディレクトリを共有(/path/to/src -> /share)

0. Xdebug によるリモートデバッグの仕組み

リモートデバッグを設定する前に PhpStorm と Xdebug がどのように通信するかを見ておきます。これを理解しておくと設定がスムーズです。

下記は、Xdebug の公式サイトに掲載されている図です。ここでは、左の「IDE」が PhpStormが起動しているホスト、右の「PHP/Xdebug」が Vagrant で構築した VM と考えて下さい。

VM に HTTP リクエストが来て、PHP スクリプトの実行がはじまると、PHP/Xdebug が IDE(xdebug.remote_hostで設定したホスト)に DBGP connect の通信を行います。PhpStorm ではこの通信を受け取り、以後は DBGP で相互に通信してリモートデバッグを実現します。

xdebug-remote-debug

ここで大切なのは、PHP/Xdebug(VM)から、PhpStorm へ DBGP connect の通信が来るという点です。これは Web でも CLI でも同じで、PHP スクリプトが VM で実行されると PhpStorm へ DBGP connect が送られてきて、リモートデバッグを開始することができます。(xdebug.remote_autostart= Onを設定した場合)

もし、うまく動かない場合などは、この点を意識して調査すると良いです。

では、実際に設定を行っていきましょう。

1. VM での設定

まず、VM にインストールされている PHP にリモートデバッグ用の設定を行います。通常は、VM を構築する際に実行するプロビジョニングに以下を含めておきます。

Xdebug が必要になるので、下記のコマンドなどで、インストールしておいて下さい。

$ yum -y install php-pecl-xdebug

1-1. php.ini(xdebug.ini)

Xdebug の設定を php.ini 等で以下のように設定します。

xdebug.remote_enable = On
xdebug.remote_autostart = On
xdebug.remote_host = 192.168.33.1
  • xdebug.remote_enableで、リモートデバッグを有効にします。
  • xdebug.remote_autostartを On にすることで、リモートデバッグが常に開始されるように設定します。任意のタイミングだけ開始することもできるのですが、開発環境なので、VM側では常に開始されるようにしておき、実際にデバッグを行うかどうかは PhpStorm 側で操作します。
  • xdebug.remote_hostで、デバッグクライアントの IP を指定します。Vagrant の private network で 192.168.33.xxxを設定しているので、ホスト側の IP として192.168.33.1を設定しています。

1-2. 環境変数

CLI アプリケーション(phpunitコマンドでのテストを含む)でのデバッグを行うために、環境変数PHP_IDE_CONFIGを設定します。

CLI アプリケーションを実行するユーザでPHP_IDE_CONFIG環境変数を定義したいので、ここでは、vagrant ユーザの ~/.bashrc に設定しておきます。

192.168.33.41の部分には、VM の IP を指定しておきます。

export PHP_IDE_CONFIG="serverName=192.168.33.41"

もし、apache ユーザで CLI アプリケーションを実行するなら、httpd.conf 等の SetEnv などで設定すると良いでしょう。

2. PhpStorm での設定

PhpStorm でリモートデバッグクライアントの設定を行いましょう。

2-1. PHP Remote Debug

まず、メニューの [Run] – [Edit Configurations…] をクリックして、[Run/Debug Configurations] ダイアログを開きます。

次にダイアログ左上にある [+] をクリックして、[PHP Remote Debug] を選択します。すると、下記のように PHP Remote Debug の設定フォームが表示されます。ここでリモートデバッグの設定を入力していきます。

phpstorm-run-debug-configurations

Name には、この設定の名称を指定します。ここではVagrantとしています。

Servers には、PHP サーバをプルダウンで選択するのですが、まだ設定が無いので、後ほど設定します。

Ide key は、今回は設定不要なのですが、何かしら値が必要なので、ダミー値を入力します。

2-2. Servers

Servers にサーバを追加するために、Servers のプルダウンメニュー横にある「…」ボタンをクリックします。クリックすると、[Servers] ダイアログが開きます。

[Servers] ダイアログでは、PHP アプリケーションが動作しているサーバの情報(ここでは Vagrant VM)を設定します。

ダイアログ左上にある [+] をクリックして、新規サーバを入力します。

Name には、名称を入力します。名称は何でも良いのですが、ここでは VM の IP を入力します。この値は、VM で設定した環境変数PHP_IDE_CONFIGの中で記述するserverName=の値と同じ内容にする必要があります。

Host には、VM の IP を入力します。

Use path mappings にチェックを入れます。ここでは、ローカルのファイルパスと VM でのファイルパスをマッピングを設定します。

この Vagrantfile では、ローカルの /path/to/src を VM 上では /share というディレクトリにマウントしているので、File/Directory/path/to/src を選択し、その右にある Absolute path on server/share と入力しておきます。

設定例は下記になります。

phpstorm-servers

[OK] をクリックすると Servers ダイアログが閉じます。この時に [Run/Debug Configurations] では、Servers には、現在設定したサーバが選択されています。

phpstorm-run-debug-configurations-done

最後に [OK] をクリックすると、設定が保存され、ダイアログが閉じます。これで設定は完了です。

3. 動作確認

では、実際にリモートデバッグを試してみましょう。

PhpStorm でリモートデバッグを有効にするには、[Run] – [Start Listen for PHP Debug Connections] をクリックします。クリックすると [Stop Listen for PHP Debug Connections] という表示に切り替わります。この状態で、再度クリックするとリモートデバッグが停止します。

今回の設定では、VM 側は常にリモートデバッグ可能な状態になっているので、PhpStorm でのこの操作でリモートデバッグを行うかどうかを切り替えることができます。

リモートデバッグが動作しているか確認するのに、[Break at first line in PHP scripts] にもチェックを入れておきます。

phpstorm-start-listen-for-php-debug-connections

3-1. Web アプリケーション

では、ブラウザから、VM にある PHP スクリプトにアクセスしてみましょう。(ここでは、Laravel アプリケーションを動かします。)

http://localhost/ にアクセスすると、処理が停止して、PhpStorm のデバッガが起動しました。

これは [Break at first line in PHP scripts] にチェックが入っているためで、一番はじめの行で処理が停止するようになっています。[Step Over] や [Step into] で、順にコードを実行して、PhpStorm 上で実行されている行が正しく遷移するか確認すると良いでしょう。

phpstorm-remote-debug-web

確認が終わったら、[Run…] でコードを実行する、もしくは [Stop] で停止させましょう。

3-2. CLI アプリケーション

CLI アプリケーションについてもリモートデバッグができるか確認しましょう。

vagrant ssh で、VM にログインして、何か PHP アプリケーションをコマンドラインで起動します。ここでは php artisanコマンドを実行します。

$ php artisan

すると、Web アプリケーションと同じく、はじめに実行される行で処理が停止し、PhpStorm のデバッガに制御が移ります。

phpstorm-remote-debug-cli

PHPUnit なども実行して、同様になるか確認しておくと良いでしょう。

これで、Web でも CLI でも PHP アプリケーションでリモートデバッグができるようになりました。あとは順に実行するなり、任意のコードにブレイクポイントを仕掛けるなり、デバッグを行うことができます。

なお、動作確認用にチェックしておいた [Break at first line in PHP scripts] ですが、アプリケーション実行の度に停止するのは面倒なので、普段はチェックは外しておきましょう。

4. トラブルシューティング

4-1. デバッガが起動しない

おそらく基本的な設定ミスなので、手順を再確認します。

  • xdebug 関連の設定変更後に Apache/php-fpm の再起動を行う
  • PhpStorm で[Start Listen for PHP Debug Connections]を行う

4-2. デバッガは起動するのに、ステップ実行できない

PhpStorm の [Servers] 設定のパスマッピングの設定を見直します。

4-3. Cannot accept external Xdebug connection: Cannot parse the value of ‘$_SERVER[‘PHP_IDE_CONFIG’]’

CLI アプリケーションでリモートデバッグを行う際に発生しました。
環境変数PHP_IDE_CONFIGが正しくセットされていなかったので、VM 側の設定を見直します。

さいごに

PhpStorm から Vagrant で構築した VM へのリモートデバッグ設定について見てきました。

はじめは面倒に見えますが、慣れてくればかなり楽に設定できます。VM 側の設定は、プロビジョニングに記述しておくと良いでしょう。

やはり、処理の流れはデバッガを使った方が掴みやすいので、ぜひ活用してみてください。

参考

http://www.jetbrains.com/phpstorm/webhelp/run-debug-configuration-php-remote-debug.html
http://www.karakaram.com/phpstorm-vagrant-remote-debug
http://blog.jetbrains.com/webide/2012/03/new-in-4-0-easier-debugging-of-remote-php-command-line-scripts/

  • コメント (Close): 0
  • トラックバック (Close): 0

Laravel の Queue で非同期処理を実装する(beanstalkd / IronMQ / SQS)

この記事の所要時間: 1654

Laravel で実装されている Queue について見てみました。

laravel

Laravel では Queue を使うことで、時間がかかる処理や、時間差で実行したい処理を非同期で実行することができます。

Laravel 4.2 の Queue では、以下の 5 つのキュードライバをサポートしています。

  • sync
  • Beanstalkd
  • Amazon SQS
  • IronMQ
  • Redis

ここでは、sync、Beanstalkd、IronMQ、Amazon SQS について試してみました。

Laravel での設定

Laravel で Queue を使うには、app/config/queue.phpにて、利用するキューエンジンの選択、設定を行います。

もちろん他の設定と同じく、app/config/local/queue.phpapp/config/production/queue.phpなど、環境に応じて設定を切り替えることも可能です。

下記が設定例です。defaultでは利用するキュードライバを指定します。指定できる値は、sync, beanstalkd, sqs, iron, redis の 5 種類です。

connectionsキーでは、それぞれのドライバについて接続情報を指定します。下記では、beanstalkdの接続情報を指定しています。

return [
    'default' => 'beanstalkd',
    'connections' => [
        'beanstalkd' => [
            'driver' => 'beanstalkd',
            'host' => 'localhost',
            'queue' => 'default',
            'ttr' => 60,
        ],
    ],
];

キューへジョブを登録

キューへのジョブを登録するには、Queueクラスのpushメソッドを使います。

第一引数にはジョブを実行するワーカーのクラス名を、第二引数にはワーカーに渡すパラメータを指定します。

use CarbonCarbon;

Queue::push('MyWorker', ['message' => 'Hello!', 'date' => Carbon::now()]);

ここでは、ワーカーのクラス名のみを指定しているため、ジョブを実行する際はfireメソッドが呼ばれます。他にもMyWorker@doJobとすることで任意のメソッドを実行したり、クロージャを渡して、そのクロージャをワーカーとして実行したりできます。

詳しくはドキュメントを参照してください。

http://laravel.com/docs/queues
http://laravel4.kore1server.com/docs/42/queues

ワーカーの実装

ジョブを処理するワーカーとしてMyWorkerクラスを実装します。ワーカーは特定のクラスを継承する必要はなく、 POPO(Plain Old PHP Object)で良いです。

MyWorkerクラスにはfireメソッドを実装します。ジョブがキューに登録されると、リスナーからこのメソッドが呼ばれます。

第一引数にはジョブインスタンス、第二引数では、Queue::push()の第二引数で指定したパラメータが渡されます。ただ、このパラメータはジョブに入る時にjson_encode()されるので、オブジェクトのインスタンスはプロパティの連想配列となります。

下記の実装では、渡されたパラメータを元に文字列を生成して、echoで標準出力へ出力しているだけです。

ジョブが正常に完了したら、delete()メソッドで、ジョブを削除しておきます。これを行わないと同じジョブが何度も実行されています。

<?php
use CarbonCarbon;
use IlluminateQueueJobsJob;

class MyWorker
{
    /**
     * @param Job $job
     * @param array $data
     */
    public function fire(Job $job, array $data)
    {
        echo sprintf('[%s] %s at %s', Carbon::now(), $data['message'], $data['date']['date']) . PHP_EOL;
        $job->delete();
    }
}

キューの監視

キューを監視してワーカーを起動するリスナーを起動します。

Laravel では artisan コマンドですでに用意されているのでこれを利用します。

php artisan queue:listenコマンドを実行すると、キューを監視状態になります。この状態でキューにジョブが登録されていると、自動でワーカーが起動して処理が実行されます。

$ php artisan queue:listen

この状態でジョブが登録されると下記のように出力されます。

$ php artisan queue:listen
[2014-08-14 16:52:35] Hello! at 2014-08-14 16:52:34.000000
Processed: MyWorker

このプロセスが終了しているとキューにジョブが登録されても実行されないので、supervisor や monit などで常時起動するように設定しておくと良いでしょう。

一定時間後に実行するジョブ

Queue::push()で登録したジョブは、リスナーが感知するとワーカーが起動して実行されます。

それとは別に、Queue::later()というメソッドを使うと、一定時間経過後に実行するジョブを登録することができます。

第一引数には、ジョブの実行を開始する時間を指定します。数値を渡すと秒数として認識され、その秒数が経過した際にジョブが実行されます。Carbonクラスのインスタンスを渡すとCarbonクラスで指定された日時に実行されるジョブとして登録されます。

第二引数と第三引数は、Queue::push()の第一引数と第二引数と同じです。

下記の例では、10秒後に実行されるジョブを登録しています。

Queue::later(10, 'MyWorker', ['message' => 'Delayed', 'date' => Carbon::now()]);

リスナー側では下記のような出力になります。[]内の日時と、atの後ろの日時で 10 秒ずれていることが分かります。

$ php artisan queue:listen
[2014-08-14 16:52:45] Delayed at 2014-08-14 16:52:34.000000
Processed: MyWorker

これはローカルの beanstalkd での実行なのでずれが無いですが、IronMQ を利用した際は、数秒のずれがありました。多少のずれは発生するので、それを認識した上で利用すると良いでしょう。

サポートしているキュードライバ

Laravel でサポートしているキュードライバ(Redisを除く)を見てみましょう。

sync

デフォルトで指定されているドライバです。

仕組みとしてはキュー、ワーカーの流れを通るのですが、ジョブが登録されると、即時にワーカーが実行されます。

非同期処理にはならないので、実際にキューを使う場面では、他のドライバを利用する必要があります。

Beanstalkd

Beanstalkd は、オープンソースのキューイングシステムです。

利用するには、Beanstalkd 自体のインストールが必要になります。

Beanstalkd は、yum などパッケージでも公開されているので、利用するプラットフォームごとに選択してインストールすると良いです。

ここでは OSX 環境を想定して、Homebrew でインストールします。

$ brew install beanstalkd

beanstalkd を起動します。デフォルトではポート11300で待ち受けます。

$ beanstalkd

なお、beanstalkd は、デフォルトではキューの情報を永続化しません。このままだと beanstalkd が落ちるとキューの情報が消えてしまうので、本番環境などで運用する際は、永続化するように設定を行うのが良いです。

http://kr.github.io/beanstalkd/

Laravel で利用する際は、composer で下記のパッケージを追加しておきます。pda/pheanstalk は、3.x がリリースされていますが、Laravel 4.2 は、2.x 系にしか対応していないので、バージョン番号に注意して下さい。

"require": {
  "pda/pheanstalk": "~2.1.0"
}

IronMQ

Iron.io が提供しているメッセージキューサービスです。

ブラウザから登録するだけで利用することができます。基本は有償サービスなのですが、無料プランが用意されており、1,000,000APIリクエスト/月まで利用することができます。

グラフィカルな管理画面が用意されており、キューの状況などが分かりやすいのが良いです。

Heroku の Addon としても提供されているので、Heroku へデプロイするなら簡単に連携することができます。

Laravel で利用する際は、composer で下記のパッケージを追加しておきます。

"require": {
  "iron-io/iron_mq": "~1.5.1"
}

下記が Heroku 環境で IronMQ を利用する際の設定例です。Heroku では、接続情報が環境変数で提供されてるので、それらをtokenprojectに設定しています。

return [
    'default' => 'iron',
    'connections' => [
        'iron' => [
            'driver' => 'iron',
            'host' => 'mq-aws-us-east-1.iron.io',
            'token' =>  getenv('IRON_MQ_TOKEN'),
            'project' => getenv('IRON_MQ_PROJECT_ID'),
            'queue' => 'sample',
            'encrypt' => true,
        ],
    ],
];

AWS US-EastAWS EU-WestRackspace ORDRackspace LONのインスタンスを利用することができます。日本国内のインスタンスは存在しないので、国内のアプリケーションからキューを登録する場合はレイテンシが気になるかもしれません。

http://www.iron.io/

SQS

AWS のメッセージキューサービスです。

こちらも管理画面からキューを作成するだけで利用することができます。有償サービスですが、無料枠が用意されており、100万件キューイングリクエスト/月まで無料で利用することができます。

東京リージョンを利用できるので、アプリケーションサーバが国内にあるなら利用しやすいですね。

Laravel で利用する際は、composer で下記のパッケージを追加しておきます。

"require": {
  "aws/aws-sdk-php-laravel": "1.*"
}

設定例は下記です。ここでは、アクセスキーやシークレット、エンドポイントURL を環境変数で渡しています。AWS ではおなじみですが、regionにキューを作成したリージョンを指定するのを忘れないようにしましょう。

    'default' => 'sqs',
    'connections' => [
        'sqs' => [
            'driver' => 'sqs',
            'key' => getenv('AWS_ACCESS_KEY_ID'),
            'secret' => getenv('AWS_SECRET_ACCESS_KEY'),
            'queue' => getenv('AWS_SQS_URL'),
            'region' => 'ap-northeast-1',
        ],
    ],

http://aws.amazon.com/jp/sqs/

ユニットテスト

キューにジョブを登録する側のテストについてです。

QueueクラスをshouldReceiveメソッドでモック化して、テストするのが手軽です。

<?php
use CarbonCarbon;

/**
 * Class QueueTest
 */
class QueueTest extends TestCase
{
    /**
     * @test
     */
    public function queuePush()
    {
        $now = Carbon::create(2014, 8, 13, 12, 34, 56);
        Carbon::setTestNow($now);

        Queue::shouldReceive('connected')->once();
        Queue::shouldReceive('push')->once()->with('MyWorker', ['message' => 'Hello!', 'date' => $now]);
        Queue::shouldReceive('later')->once()->with(10, 'MyWorker', ['message' => 'Delayed', 'date' => $now]);

        $this->client->request('GET', '/queue/push');

        $this->assertTrue($this->client->getResponse()->isOk());
    }
}

サンプルアプリケーション(Heroku)

このエントリの内容を実装したサンプルアプリケーションを github に公開しています。

コード自体はシンプルで、http://localhost/quque/push にアクセスするとジョブがキューに登録されます。あとは php artisan queue:listen コマンドでジョブが実行されます。

Heroku で試せるように、heroku_create というシェルスクリプトで、heroku 関連のコマンドを記述しています。このコマンドを流せば、Heroku アプリケーションが構築されます。

Heroku でのポイントは、`Procfile`で、ワーカープロセスとしてリスナーを起動するという点です。

web: vendor/bin/heroku-php-apache2 public/
worker: php artisan queue:listen

このアプリケーションを Heroku にデプロイすると、web(ジョブをキューに登録する側)、worker(リスナー)の Dyno が構築されます。

あとは Heroku の管理画面で worker の Dyno 数を 1 にすると、web 経由で登録したジョブが worker によって実行されるようになります。

https://github.com/shin1x1/laravel-queue-sample

さいごに

Laravel の Queue について見てきました。

最後に、どのドライバを使うかについてですが、開発環境では beanstalkd を利用するのが手軽で良いでしょう。ローカルにインストールするので動作も速いです。

本番環境では、要件によりけりですが、国内にアプリケーションサーバがあるなら SQS、Heroku など US リージョンを利用するなら IronMQ が良さそうです。

もちろん、自前で beantalkd や Redis を立てるのも良いですが、利用できるなら、ありものを利用するのが楽ですね。

このように、開発環境と本番環境とでドライバを変えても、コード側は一切変更する必要が無いというのは、よく出来ていますね。

参考

blog.ISHINAO.net | Laravel 4でキューを使ってみる
laravel – キュードライバにbeanstalkdを使用する – Qiita

  • コメント (Close): 0
  • トラックバック (Close): 0

「開発現場で活用するVagrant」を発表しました

この記事の所要時間: 616

JAWS-UG三都物語 2014 にて「開発現場で活用するVagrant」という発表を行いました。

jawsug-santo-2014
Photo By Yuko Oshima

5 つトラックがあるなか、テクニカルトラックでの発表でした。開放感を感じる会場で、快適にセッションを行うことができました。

発表内容

Vagrant を現場で活用していく上で参考になる情報を、と考えたところ、やはり実際に動くデモが良いと思い、デモを中心にセッションを行いました。

発表資料は、以下です。

開発現場で活用するVagrant from Masashi Shinbara

デモで利用した Varantfile などは、下記で公開しています。

https://github.com/shin1x1/vagrant-demo-20140705

デモでは、同じ PHP アプリケーションについて仮想環境やプロビジョニングツールを変えて構築を行いました。(実際に一からコードを書く時間が無かったので、できあがったものをお見せする形でした。)

Vagrant と連携ツールの整理

Vagrant の話になると、VirtualBox や Chef など多くのツールが一緒に登場してきます。

こららを頭の中で整理できていないと、カスタマイズしたり、トラブルが発生した際にどれを見れば良いかが分からない、という状況になりがちです。

セッションでは、連携ツールを「仮想環境」と「プロビジョニング」に分けて整理してみました。

開発現場で活用するVagrant-1

vagrant up だけ、にこだわる

セッションでもお話したのですが、Vagrant で開発環境を構築する際に大事なのは、「vagrant upコマンドだけで環境を作る」ということです。

デモでは、Ansible でプロビジョニングを行う箇所もあったのですが、Ansible はホスト側にはインストールせず、ゲスト側(仮想マシン)にシェルスクリプトでインストールして、仮想マシン内でローカルコネクションでプロビジョニングを行うようにしました。

provision = &lt;&lt;-EOT
    rpm -ivh http://ftp.riken.jp/Linux/fedora/epel/6/i386/epel-release-6-8.noarch.rpm
    yum -y install ansible libselinux-python
    ansible-playbook /vagrant/provision/vagrant.yml --connection=local
EOT

config.vm.provision :shell, :inline =&gt; provision

Vagrant で開発環境を作れば、チーム内で誰の環境でも同じ環境を持つことができます。

それなのに、Vagrant や VirtualBox など最低限なツール以外のものをホストに要求すると、それらをインストールする手間も発生しますし、ホストの差異による挙動の違いやバージョンにも気を払う必要が出てきます。

仮想マシン内に閉じ込めておけば、インストールは自動で行うことができ、考慮すべきプラットフォームも一つ(仮想マシンのみ)で済みます。

せっかく、Vagrant で開発環境の構築が自動化されているのに、それを動かすためのツールで手間がかかるというのはもったいない気がします。

これはコマンドについても同じです。環境構築ではvagrant upのみを実行するようにします。それ以外のコマンドはプロビジョニングに含めて、仮想マシン内で実行します。

Vagrant で開発環境を作るのであれば、ホストには、必要最低限(Vagrant と VirtualBox)のツールだけをインストールして、vagrant upコマンドだけで構築ができるようにプロビジョニングの内容を組み立てるようにしましょう。

発表中に Yo をもらう

セッション開始前に、Yo のアカウントを公開して、発表中に少しでも「いいね!」と思う箇所があれば、Yo を送って下さいと呼びかけてみました。

会場では、そもそも Yo をインストールしている方が数人だけだったのですが、デモの際に何度も Yo を送ってもらいました。

ポケットの中で、iPhone が震える度に、「あー伝わってるなあ」と安心することができ、楽しくセッションを進めることができました 😀

これ、意外に嬉しいので、発表される方は、試してみると良いですよ。

Yo を送って下さったみなさん、ありがとうございましたm(_ _)m

さいごに

おかげさまで Vagrant に関する発表を、とお声がけ頂く機会が何度もあるので、色々と手を変え品を変えといった感じで試行錯誤しながらやっているところです。

このあたりは変化も早く、色々と新しい内容が出てくるので、毎回資料を作りながら発見もあり、面白いですね。

やはり今後は Docker との絡みが面白くなりそうなので、また機会があれば話してみたいと思います。

セッション中に頂いた tweet

ありがとうございました!

  • コメント (Close): 0
  • トラックバック (Close): 0

「PHPコードではなくPHPコードの「書き方」を知る」を発表してきました

この記事の所要時間: 27

PHPカンファレンス関西2014で「PHPコードではなくPHPコードの「書き方」を知る」を発表してきました。

IMG_0020
写真提供:久岡写真事務所

別トラックに人気セッションがひしめく中、多くの方に聴いて頂き、ありがとうございましたm(_ _)m

発表内容

PHP 中級者(中級がどこかというのはありますが)を目指す初心者の方を対象に、FizzBuzz のコードを、関数にまとめて、クラス化するというのをライブコーディングで行いました。

また、関数にまとめた段階で、自動テストを書いて、実行結果を目で確認するのではなく、テストを実行して確認するというスタイルを取りました。

発表資料は以下です。

コードを書きながら進めていく形なので、資料だけでは少し伝わらない部分があるかもしれません。

PHPコードではなく PHPコードの「書き方」を知る from Masashi Shinbara

デモで書いた PHP コードは、GitHub で公開しています。Sample1, Sample2 とディレクトリが分かれています。上記資料には、対応するディレクトリを記載しているので、参考にしてみて下さい。

https://github.com/shin1x1/how-to-write-php-code-with-fizzbuzz

PhpStorm のプレゼンテーションモード

ライブコーディングには、PhpStorm のプレゼンテーションモードを使いました。エディタペインが全画面表示になるので、ライブコーディングには最適ですね。

phpstorm_presentation_mode

プレゼンテーションモードの起動は、command + shift + a で [Enter action or option name] を表示して、「presen」まで入力して、[Toggle Presentation mode]を実行しています。

phpstorm_toggle_presentaion_mode

プレゼンテーションモードから復帰する際も同じ操作を行います。

さいごに

準備の段階では、発表内容から先に進めて、処理の部分と出力の部分を別クラスにして、それを FizzBuzz に DI して、インターフェースに切り出して、インターフェースは同じだが振る舞いの異なるクラスとの差し替えてなど、発展させていっていたのですが、時間の関係もあり、削りました 😀

今回のように、誰かがコードを書いたり、操作をしたりというのを、生で見る、というのも、セッションの一つの面白さだと思うので、そこが伝わっていれば嬉しいです。

  • コメント (Close): 0
  • トラックバック (Close): 0

Laravel DB テーブルの簡易メンテ画面を作る Laravel-Table-Admin を作りました

この記事の所要時間: 532

laravel

マスタテーブルのメンテナン画面は、単純な CRUD 画面なのですが、テーブル数が多いと、いちいち作るのも手間がかかります。

そこで、Laravel のパッケージとして、Laravel-Table-Admin を作りました。

https://github.com/shin1x1/laravel-table-admin

Laravel の対象バージョンは、4.1 以降としています。

何をするものか

マスタテーブルのメンテナンス画面など、ごく単純な CRUD 画面だけを作るパッケージです。

作るといっても、コードジェネレータではなく、設定を行えば、自動でテーブルスキーマから画面を動的に構築します。CakePHP の Scaffold と似た発想です。

いわば、機能がごくシンプルになった phpMyAdmin / phpPgAdmin を Laravel アプリケーションに組み込めるというものです。

百聞は一見に一見に如かずなので、画面キャプチャを。

一覧画面です。

classes-1

編集画面です。

classes_edit-1

外部キーがある場合は、参照先テーブルの内容がプルダウンで選択できます。

riders-1

デモアプリケーションを公開しています。こういった画面を簡単に作ることができます。

http://laravel-table-admin.herokuapp.com/crud/classes

インストール

Composer でインストールします。

composer.json に以下を追加して、composer install or update して下さい。

{
    "require": {
        "shin1x1/laravel-table-admin": "~0.1.0"
    }
}

app/config/app.phpに ServiceProvider と Facade を追加します。

 'providers' => [
      // ....
      'Shin1x1\LaravelTableAdmin\TAbleAdminServiceProvider`
  ],
 'aliases' => [
      // ....
      'TableAdmin' => 'Shin1x1\LaravelTableAdmin\TableAdminFacade',
  ],

あとは、app/routes.php で、このパッケージで CRUD 画面を表示する対象のテーブルを指定するだけです。下記では、classes, nationalities, riders という3つのテーブルについて CRUD 画面を表示します。

TableAdmin::route([
    'classes',
    'nationalities',
    'riders',
]);

URL は、http://localhost/crud/{TABLE} になります。{table}の部分が、上記で指定したテーブル名になります。

これで、URL にブラウザからアクセスすると CRUD 画面が表示されます。

デモアプリケーションのコードも公開していますので、参考にして下さい。

https://github.com/shin1x1/laravel-table-admin-example

対象データベース

MySQL と PostgreSQL を対象としています。

対象テーブル

今のところ、プライマリキーがidで、一覧やプルダウンメニューでの表示カラムはnameに固定しています。

多くの場合、これで問題無いと思いますが、ニーズがあれば、設定で変更できるような対応も考えています。

実用する際のポイント

実際のところ、この画面は管理者用機能になるでしょう。TableAdmin::route()での指定では、Route::group()などを使って、認証をかけると良いでしょう。

// admin フィルターがあるとして
Route::group(['before' => 'admin'], function() {
    TableAdmin::route([
        'classes',
        'nationalities',
        'riders',
    ]);
});

Laravel-4-Generators

同様のことを行う Laravel パッケージとしては、Laravel-4-Generators が有名です。

これはとても便利なパッケージで、私も migration file のジェネレータとして良く利用しています。

大きく異なるのは、Laravel-4-Generators は、コードジェネレータですが、Laravel-Table-Admin はコードの生成は行なわず、動的にテーブルスキーマを読んで、画面を組み立てています。

双方とも良し悪しはあるのですが、動的に画面を生成した方が、画面デザインの修正などを一箇所で行うことができるので、後であれこれ変更する際は楽だと判断しました。

Laravel-4-Generators は、バージョン2 以降には、ビューテンプレートのジェネレートで、一覧画面やフォーム画面の詳細部分が生成されなくなりました。これにより、単純にジェネレートしても、CRUD画面が作れなくなっています。これも本パッケージを作ろうと思った動機の一つです。

さいごに

自分が欲しかったので、作ってみました。今のところ、必要最低限を実装したという状態です。

あとは、付加機能(一覧での検索や並び替え、テーブルカラムの対応等)を足していこうと思っています。コントリビュートもお待ちしています:D

https://github.com/shin1x1/laravel-table-admin

  • コメント (Close): 0
  • トラックバック (Close): 0

はじめてのPHPカンファレンス関西

この記事の所要時間: 540

いよいよ、今週末にPHP カンファレンス関西 2014が開催されます。

8937271164_f52e8831af_z
Photo by tenshow

今年で、4 回目の開催となるのですが、こうしたイベントに初めて参加する、という方も多いのではないでしょうか。

そこで、リレーブログ 12 日目の今日は、はじめてカンファレンスに参加する方に向けて、気になるあれこれを書いてみたいと思います。

(昨日のリレーブログは、@tanakahisateru さんの うまれかわるMVC 〜PHPカンファレンス関西2014にむけてでした。)

服装

いきなり服装?という人がいるかもしれませんが、実は初めてだと気になったりします。

みんなスーツとかだったらどうしよう。いちおうジャケットくらい羽織ろうかな、いや、Tシャツとデニムの人ばかりだと浮くかも、うーーん。。。

分かります。ちゃんとしてる人ほど気になるポイントですね。

はい、お答えしましょう。

外を出歩く一般的な服装であれば、何でも ok です。

休日にヨドバシカメラに行く服装だと思って貰えれば良いかと。

カジュアルな方が多いですが、中にはジャケットを羽織っている方もいますし、このあたりは日頃の服装ですね。

気軽な服装でお越し下さい 😀

会場へのアクセス

まずは、会場へアクセスについて。

公式サイトに地図があるので、こちらを参考に。地下鉄でいうと堺筋本町駅から歩くのが良いですね。駐車場等はあまり無いので、公共交通機関で行きましょう。(懇親会がありますしね!)

http://conference.kphpug.jp/2014/#access

駅を降りて、迷ってしまうという人は、下記リンクをスマートフォンで開けるようにしておきましょう。会場の方角を指してくれるので、この指示どおり歩けば、会場に向かうことができます。

https://bit.ly/phpcon_kansai

来場時間

会場に来る時間帯ですが、10:00 開場となっていますので、10:00 頃に来て頂ければ大丈夫です。

なお、1F には(小さいですが)カフェがあるので、早めに来て、こちらで朝ごはんを食べるというのも良いですね。(堺筋本町駅から会場までの道中でも、カフェが何件かあったはず)

受付

会場に着いたら、まず受付をしましょう。受付は、4F で行っています。(6Fもセッション会場ですが、受付は 4F なのでお間違い無く。)

まずはエレベータで 4F へどうぞ。

セッション

セッションは、しっかり話を聞いて、楽しみましょう。

学校の授業ではないので、かしこまって聞く必要はありません。面白いところは笑い、気になることは質問してみても良いですね。

基調講演の後は、マルチトラックになるので、聞きたいセッションに移動します。6F のセッションは、定員が少なめなので、どれにしようかなと迷ってる内に埋まってしまう可能性があります。

事前にどのセッションに行くか決めておくと良いです。

昼ごはん

さて、午前のセッションが終わって、昼ごはんです。

昼ごはんは、会場周辺のご飯屋さんに行きます。昼時は混んでしまうので、昼一で聴きたいセッションがある人は時間を気にしながら昼食を取りましょう。

出展ブースと丸善&ジュンク堂

セッションの合間には、出展ブースに立ち寄ってみましょう。

色々なデモや展示があるので、セッションとはまた違った楽しさがあります。ステッカーなどノベルティの配布もあるので、それらを集めて回るのも良いですね。

また、今回は、丸善&ジュンク堂さんの出張販売ブースがあります!

話題の技術書を販売して頂けるので、この機会にぜひ手にとってみて下さい。書籍を執筆された方によるサイン会なども企画しているので、ぜひ直接お話をしてみて下さい。

電源、WiFi

いまどき気をつけておきたいのが、電源と WiFi についてです。

残念ながら、参加者用のインターネット回線(WiFi)は、用意していません。ご了承下さい。

また、電源についても、一部ではご用意していますが、皆さんが充電できるほどではありません。譲り合って利用して頂くようにお願いします。

Twitter / Facebook

もちろん、Twitter や Facebook でも交流できるチャネルを用意していますよ。

Twitter の公式ハッシュタグは「#phpkansai」です。関西PHP勉強会と共通なので、すでに tweet が流れていますね。

当日は、トラックごとにハッシュタグを設ける予定です。セッション内容については、トラック専用のハッシュタグと「#phpkansai」を両方付けると良いです。

Facebook には、参加者の方同士で交流できるようにグループを作成しました!カンファレンスに参加される方であれば、どなたでもどうぞ。

https://www.facebook.com/groups/218826904993793/

ぼっちだけど…

イベントに意気込んで参加したものの、なんだか周りは仲良さそうで、楽しそう。自分だけ一人でなんだかなあ、ということがあります。

わかります。

そんな時は、まずは「ぼっちでも ok」と思いましょう。一人で参加して、誰とも話さず帰る。全然 ok です。セッションやブースを楽しめれば、それで ok 。何ら問題無しです。ぼっち上等。

でも、少しでも誰かと話したいなあという人は、ちょっぴり勇気を出して話してみましょう。

話しかけるのが難しければ、Twitter や Facebook で、これこれの話がしてみたい、とか投稿するだけでも良いです。参加者はわりと見ているので、誰かが返信をくれるかもしれません。少しでもやりとりがあれば、面と向かっても話しやすいものです。

そういった意味では、当日までに、Twitter や Facebook で自己紹介がてら何か投稿しておくと、「あ、○○と書いてた人だ」と認識してもらえて楽ですよ。

ちなみに以前、下記のようなエントリを書きました。ぼっちで少し不安という人は、読んでみて下さい。

懇親会を楽しむ5つの方法

いよいよ今週末!

さあ、今週末にはカンファレンス当日になります。

これ不安だな、気になるなという方は、Twitter で「#phpkansai」を付けて tweet するか、Facebook グループへ投稿して下さい。

当日は一緒に楽しみましょうー!

ちなみに、私は、スタッフもやりますが、午後に「PHPコードではなく、PHPコードの「書き方」を知ろう」という発表も行います。セッションに参加される方、よろしくお願いします!

リレーブログ、明日は @msng さんの 頭ん中 ですー。

  • コメント (Close): 0
  • トラックバック (Close): 0

Heroku で作るスケーラブルな PHP アプリケーション

この記事の所要時間: 221

第16回関西PHP勉強会で、「Heroku で作るスケーラブルな PHP アプリケーション」という発表をしてきました。

heroku-logo-light

発表資料

Heroku でちゃんと動く PHP アプリケーションを作ると、自然とスケーラブルな構成になりますよ、という内容です。

会場でも、Heroku 自体は知っているが、まだ使ってはいないという人が多かったので、細かな Tips は省いて、こういった構成でやりますよというイメージをお話しました。

実際に構築する上での Tips などは、また別の機会に話してみたいです。

サンプルアプリケーション

サンプルアプリケーションとして、簡単な画像アップロードサイトを Laravel 4.2 で作りました。

https://github.com/shin1x1/laravel-on-heroku

アプリケーションデータは、以下のアドオンへ保存するようにしています。画像ファイルは、アドオンではなく、S3 に保存しています。

  • データベース = Heroku Postgres
  • ログ = Papertrail
  • セッションストレージ = Redis To Go
  • 画像ファイル = S3(AWS)

使い方は、README.md に記載しているのですが、Heroku 関係は、heroku_create というシェルスクリプトにまとめています。

これを流せば、Heroku アプリケーションの作成、環境変数追加、アドオン追加などをひと息で行うことができます。

#!/bin/sh

heroku create -r heroku
heroku config:set LARAVEL_ENV=heroku

heroku addons:add heroku-postgresql
heroku addons:add newrelic:stark
heroku addons:add scheduler
heroku addons:add sendgrid
heroku addons:add redistogo
heroku addons:add papertrail
heroku addons:add librato

デモ用に Heroku にデプロイしています。

http://infinite-caverns-8536.herokuapp.com/

さいごに

Heroku は、無料から使えるのが良いですね。アドオンも機能制限(保存レコード数等)版ながら無料で使えるものが多いので、アプリケーションからの連携を試すことができます。

スケーラブルな PHP アプリケーションを作る練習場として、Heroku を触ってみるというのも面白いですよ。

  • コメント (Close): 0
  • トラックバック (Close): 0

PHP で配列を走査して処理するのは、for / foreach だけじゃない

この記事の所要時間: 918

PHP で配列の要素にアクセスして、処理を行うには、for や foreach を使うのがおなじみです。

php-logo

この方法でも良いのですが、PHPには、それ以外にも配列を走査する関数やライブラリがあります。ここでは、配列を走査して処理を行う方法を見てみましょう。

サンプル仕様

このエントリで以下の配列を処理対象とします。array.phpで保存されている想定です。

<?php
return [
    [
        'id' => 1,
        'year' => 1993,
        'name' => 'Harada',
    ],
    [
        'id' => 2,
        'year' => 2001,
        'name' => 'Kato',
    ],
    [
        'id' => 3,
        'year' => 2009,
        'name' => 'Aoyama',
    ]
];

この配列について処理を行います。

  • 配列内に連想配列が格納されており、nameyearというキーを持つ
  • yearが、2000以上の要素のみ、結果配列に格納する
  • 結果配列には、nameyearを連結した文字列を格納する

求める結果は、以下になります。

array(2) {
  [0] =>
  string(8) "2001Kato"
  [1] =>
  string(10) "2009Aoyama"
}

foreach を使う

まずは、foreach を使う方法です。よくある手続き的なPHPコードですね。foreachで配列を回して、yearが2000以上の場合だけ、結果配列に値を入れています。

<?php
$array = include('array.php');

$result = [];

foreach ($array as $v) {
    if ($v['year'] <  2000) {
        continue;
    }

    $result[] = $v['year'] . $v['name'];
}

var_dump($result);

array系関数を使う

次に、filter と map を使って、実装します。PHP には、array_maparray_filter関数があるので、これを使います。

実装は下記になります。array_filterarray_mapを使うので、それぞれ配列の要素をフィルタリングする、要素に処理を行い、結果配列を格納するといった意図がより明確になります。

ただ、array_fileterarray_mapで引数の順序が異なるのと、2 行に分かれており、中間の結果を保持する一時変数が必要になるのが難点です。

<?php
$array = include('array.php');

$tmp = array_filter($array, function($v) {
    return $v['year'] >= 2000;
});

$result = array_map(function($v) {
    return $v['year'] . $v['name'] ;
}, $tmp);

var_dump($result);

試しに 1 行にまとめると下記になります。一見良さそうですが、このコードをぱっと見て、array_filterが先に適用されるのと認識できるでしょうか。

$result = array_map(function($v) {
    return $v['year'] . $v['name'] ;
}, array_filter($array, function($v) {
    return $v['year'] >= 2000;
}));

Laravel(Illuminate\Supportパッケージ)を使う

filter / map を使う別の例として、Illuminate\Supportパッケージ のIlluminate\Support\Collectionクラスを使います。

https://github.com/illuminate/support

Illuminate\Support パッケージは、Laravel を構成しているパッケージの一つで、フレームワークを使わずとも、このパッケージ単体でも利用することができます。

インストールするには、composer.jsonに以下のように指定して、composer installもしくはcomposer updateを実行します。

{
    "require": {
        "illuminate/support": "~4.2"
    }
}

Illuminate\Support\Collectionを使うことで、メソッドチェインで配列を操作することができます。

実装すると下記のようになります。filterメソッドでフィルタリングを行い、その結果配列に対してmapメソッドを実行して、結果配列の要素を作成していることが分かります。

<?php
use IlluminateSupportCollection;

require_once __DIR__ . '/vendor/autoload.php';

$array = include('array.php');

$result = Collection::make($array)->filter(function ($v) {
    return $v['year'] >= 2000;      // filter

})->map(function ($v) {
    return $v['year'] . $v['name']; // map

})->toArray();

var_dump($result);

Ginq を使う

Illuminate\Support\Collectionと似た機能を持つライブラリに、Ginq があります。こちらもメソッドチェインで配列への操作を行うことができます。

https://github.com/akanehara/ginq

インストールするには、composer.jsonに以下のように指定して、composer installもしくはcomposer updateを実行します。

{
    "require": {
        "ginq/ginq": "~0.1"
    }
}

Ginq を使って、実装すると、下記のようになります。配列を取り込むところ以外は、Illuminate\Support\Collectionと全く一緒になりました。

<?php
require_once __DIR__ . '/vendor/autoload.php';

$array = include('array.php');

$result = Ginq::from($array)->filter(function ($v) {
    return $v['year'] >= 2000;      // filter

})->map(function ($v) {
    return $v['year'] . $v['name']; // map

})->toArray();

var_dump($result);

さいごに

4 つのパターンで配列を走査して、結果配列を求めるという処理を書いてみました。

foreach は、配列の要素を走査していくという汎用的な役割なので、そのループの中で様々な処理を書くことができます。一方、array系関数やライブラリは、それぞれのメソッドで用途や目的が決まっているので、どのような処理を行い、結果、どのような解を求めているのが分かりやすいです。

また、filter や map という概念は、多くのプログラミング言語で利用されており、こうした概念をおさえておくと、別の言語でコードを書いたり、読んだりする際に、意図を汲むことができ理解しやすくなります。

foreach で書くことがダメだというわけではなく、それ以外の書き方が、PHPにもあるということを知っておくということが大事ですね。

Illuminate\Support\Collection と Ginq

Illuminate\Support\Collection と Ginq は、Linq to Object ライクなインターフェースを持ち、実際に使い方も似ています。

ただ、この2つで大きく違うのが、評価のタイミングです。

Illuminate\Support\Collection は、mapメソッドを実行したタイミングで即時に評価され、処理が行われます。

一方、Ginqは、遅延評価となっており、mapメソッドを実行してもすぐに map 処理が行われません。このエントリの例では、toArray()が実行されたタイミングで、はじめて map 処理が行われます。

実際に利用する際は、この評価タイミングの違いは、意識しておく必要があります。

参考

迫り来る「forおじさん」と呼ばれる時代

  • コメント (Close): 0
  • トラックバック (Close): 0

PHP 定義されている情報(クラス、関数、変数等)を取得する関数まとめ

  • 2014-06-04 (水)
  • PHP
この記事の所要時間: 124

PHP には、定義されているクラスや関数、変数などの一覧を取得する関数があります。

php-logo

ここでは定義情報を取得できる関数群をまとめてみました。ここでは実行例として、Laravel アプリケーションのビューテンプレート(hoge.blade.php)で実行した内容を記載しています。

定義された情報を取得する関数群

get_defined_constants()

定義されている定数を連想配列として取得します。キーが定数名で、要素がその値となっています。

http://www.php.net/manual/ja/function.get-defined-constants.php

出力してみると、1771 個の定数がありました。内容を見ると、フレームワークやアプリケーションで定義されたものの他に、PHP本体や extension で多数の定数が定義されていることがわかります。

array (size=1771)
  'E_ERROR' => int 1
  'E_RECOVERABLE_ERROR' => int 4096
  'E_WARNING' => int 2
...

get_declared_classes()

定義されているのクラスの名前が配列として取得します。

http://www.php.net/manual/ja/function.get-declared-classes.php

304 個のクラスが定義されていました。

array (size=304)
  0 => string 'stdClass' (length=8)
  1 => string 'Exception' (length=9)
  2 => string 'ErrorException' (length=14)
  3 => string 'Closure' (length=7)
...

get_declared_interfaces()

定義されているインターフェイスを配列として取得します。

http://www.php.net/manual/ja/function.get-declared-interfaces.php

55 個のインターフェイスが定義されていました。

array (size=55)
  0 => string 'Traversable' (length=11)
  1 => string 'IteratorAggregate' (length=17)
  2 => string 'Iterator' (length=8)
  3 => string 'ArrayAccess' (length=11)
...

get_declared_traits()

定義されているトレイトを配列として取得します。

http://www.php.net/manual/ja/function.get-declared-traits.php

トレイトの定義が無かったので、サンプルとして Foo をトレイトとして定義しています。

array (size=1)
  0 => string 'Foo' (length=3)

get_defined_functions()

定義されている関数を連想配列として取得します。

http://www.php.net/manual/ja/function.get-defined-functions.php

連想配列には2つのキーがあり、internalには内部関数、userにはユーザ定義関数が配列として格納されています。

ここでは、1,686個(!)の内部関数と74個のユーザ定義関数がありました。

array (size=2)
  'internal' => 
    array (size=1686)
      0 => string 'zend_version' (length=12)
      1 => string 'func_num_args' (length=13)
      2 => string 'func_get_arg' (length=12)
      3 => string 'func_get_args' (length=13)
...
 'user' => 
    array (size=74)
      0 => string 'composerrequirea978da05ae47fd0758967870dd5a04f2' (length=47)
      1 => string 'composerautoloadincludefile' (length=29)
      2 => string 'crypt_random_string' (length=19)
      3 => string '_swiftmailer_init' (length=17)

get_defined_vars()

全ての定義済の変数を連想配列で取得します。

http://www.php.net/manual/ja/function.get-defined-vars.php

連想配列のキーに変数名、要素が変数値となっています。

array (size=6)
  '__path' => string '/share/app/config/../views/login.php' (length=36)
  '__data' => 
    array (size=4)
      '__env' => 
        object(IlluminateViewEnvironment)[208]
          protected 'engines' => 
            object(IlluminateViewEnginesEngineResolver)[202]
              ...
          protected 'finder' => 
            object(IlluminateViewFileViewFinder)[207]
              ...
...

get_included_files() / get_required_files()

include または require で読み込まれたファイル名を配列として取得します。

http://www.php.net/manual/ja/function.get-included-files.php

255 個のファイルが読み込まれていました。get_required_files()は、get_included_files()のエイリアスとなっているので、実行結果はどちらでも同じです。

array (size=225)
  0 => string '/share/public/index.php' (length=23)
  1 => string '/share/bootstrap/autoload.php' (length=29)
  2 => string '/share/vendor/autoload.php' (length=26)
  3 => string '/share/vendor/composer/autoload_real.php' (length=40)
...

get_loaded_extensions()

コンパイル/ロードされているモジュールを配列として取得します。

http://www.php.net/manual/ja/function.get-loaded-extensions.php

58 個のモジュールが有効になっていました。

array (size=58)
  0 => string 'Core' (length=4)
  1 => string 'date' (length=4)
  2 => string 'ereg' (length=4)
  3 => string 'libxml' (length=6)

なお、get_loaded_extensions()では、引数に真偽値を指定することができ、trueを渡すと、Zend 拡張モジュールのみを取得します。

実行してみると、下記の 2 つだけでした。

array (size=2)
  0 => string 'Zend OPcache' (length=12)
  1 => string 'Xdebug' (length=6)

ini_get_all()

設定値を連想配列として取得します。

http://www.php.net/manual/ja/function.ini-get-all.php

下記エントリで実行結果を記載していますので、ご参考まで。

http://qiita.com/shin1x1/items/f469bfb73c396007f911

使いどころ

色々と使いどころはあるのですが、便利な使い方を一つ。

フレームワークのビューテンプレートで、定義(バインド)されている変数をリストアップします。CakePHPやLaravelなどのフレームワークでは、ビューテンプレートをビュークラスのメソッドで読み込んで実行するので、ビューテンプレート内はこのメソッドのコンテキストで実行されることになります。

get_defined_vars()を使うことで、実際にはどのような変数がビューテンプレートで定義されているかを確認できます。

下記が、Laravel ビューテンプレートでget_defined_vars()を実行した例です。このビューテンプレートでは 6 つの変数が定義されており、$__path$__data$__env$app$errors$loginUserとして利用できることが分かります。

このように、マニュアルなどのドキュメントを見ずとも、コードで利用できる変数を知ることができます。

<?php var_dump(array_keys(get_defined_vars())) ?>

array (size=6)
  0 => string '__path' (length=6)
  1 => string '__data' (length=6)
  2 => string '__env' (length=5)
  3 => string 'app' (length=3)
  4 => string 'errors' (length=6)
  5 => string 'loginUser' (length=9)

他には、クロージャ内でget_defined_vars()を実行して、スコープにある変数がどれかを確認したり、PHPの挙動を知るのにも使えます。

さいごに

こういった定義を確認する関数群は日々使うというわけではありません。ただ、知っておくと、アプリケーションのデバッグや、フレームワークの挙動を確認したりする際に役立ちます。

日々開発しているPHPコードの定義情報を見てみると、新たな発見があるかもしれませんよ。

このエントリで紹介した関数群を書いたコード Gist に置いてます。参考まで。

追記

このエントリでは、配列で取得する関数を取り上げましたが、コマンドラインでも取得できます。extension で定義されているクラスや設定を見るなら、コマンドの方が手軽ですね。

$ php -h
...
  --rf       Show information about function .
  --rc       Show information about class .
  --re       Show information about extension .
  --rz       Show information about Zend extension .
  --ri       Show configuration for extension .
  • コメント (Close): 0
  • トラックバック (Close): 0

Heroku で Composer を使う時に気を付けたいこと

この記事の所要時間: 745

Heroku が PHP をサポートしたので、テストがてら Laravel アプリケーションをデプロイしてみました。

heroku-logo-light

デプロイしたのは、Doctrine を利用するアプリケーションだったのですが、ローカルでは composer でインストールできるのですが、Heroku にデプロイするとインストールされないという現象が起こりました。

Laravel での Doctrine 使用

今回のアプリケーションでは、DBのテーブルスキーマ情報を読み込んで、動的に画面を作るという処理があり、そこで Doctrine の SchemaManager を使っていました。

Laravel で、Doctrine の SchemaManager のインスタンスを取得するのは簡単で、下記のメソッドを実行するだけです。

$manager = DB::connection()->getDoctrineSchemaManager();

こんなあっさりなので、laravel/frameworkパッケージをインストールすると、Doctrine も入るものだと思ってました。

Heroku での Composer

Heroku へデプロイするコードのルートディレクトリにcomposer.jsonが含まれていると、PHPアプリケショーンとしてセットアップが行われます。(依存解決に Composer を使わない場合でも、空のcomposer.jsonが必要です。)

このcomposer.jsonでは、通常の依存関係を指定するだけでなく、実行するPHPバージョンや拡張の指定ができます。例えば、下記のようにするとPHP 5.5.12をランタイムにして、memcached拡張が利用できます。

{
  "require": {
    "php": "5.5.12"
    "ext-memcached": "*",
  }
}

この記法は、Composer としてはサポートしているのですが、Composer 自身がランタイムの変更などを行うわけではありません。

そこで、Heroku の Composer は独自拡張しているのだろうと考えました。まあ、この思い込みが惑わすわけですが。

あと、Heroku での PHP サポートは、まだベータなので、そのせいもあるのかなと思ってました。

https://getcomposer.org/doc/02-libraries.md#platform-packages

開発環境、別 PaaS では正常に動作

もちろん開発環境(OSX, Linux VM)では、Heroku にデプロイしたものと同じコード(composer.(json|lock))で問題無く動いていました。

別のPaaSを試してみようと思い、Pagodabox に設置すると、これも正常に動作しました。

Heroku と 別 PaaS で、vendor/ 以下を比べると、10個近くのパッケージがHerokuでは入っていませんでした。

なぜ Heroku だけ入らない。やっぱり、独自拡張のせい?ベータ版だから?

–no-dev!

この作業していたのが、夜中でした。Pagodabox にデプロイできたので、これで良しとして、その日は寝ました。

しかし、気になるのが、同じ現象をググっても、Laravel アプリケショーンが Heroku で動かない,
Doctrine が入らないなんて出てこないんですね。動かしてみた系の記事はあるのに。

翌日、もう一度、Heroku の公式のドキュメントを読み直すことにしました。

すると、ありました。ちゃんと書いてありました。実行する composer コマンドが。

Heroku では、下記のオプション付きで実行するようです。そう、--no-devオプション付きでね!

$ composer install --no-dev --prefer-dist --optimize-autoloader --no-interaction

早速、手元で同じオプションで実行してみると、ちゃんとDoctrineがインストールされない。

ああ、これか。。。

Heroku PHP Support | Heroku Dev Center

–no-dev オプション

composer コマンドでは、いくつかオプションを指定することができ、--no-devはその一つです。

Composer公式サイトでは、下記の記述があります。--no-devオプションを付けると、依存解決する際にcomposer.jsonrequire-devセクションの内容は解決されません。

--no-dev: Skip installing packages listed in require-dev.

デフォルトでは、--devが付いているのと同じ状態になり、require-devセクションの内容も依存解決の対象となります。

https://getcomposer.org/doc/03-cli.md#install

依存パッケージのcomposer.jsonをチェック

アプリケーションが依存しているパッケージのcomposer.jsonを洗い出してみると、require-devにDoctrineを指定しているものはいくつかあれど、requireに指定しているものは見事にありませんでした。

つまり、開発環境やPagodaboxでは、--no-dev無しだったため、require-devセクションを含んで依存解決したため、Doctrine が入っていました。

かたや、Heroku では、--no-devありだったので、Doctrine が入りませんでした。おそらく Heroku だけに入らなかった他のパッケージも同様でしょう。

[解決] require に doctrine を指定

はい、原因は分かったので、解決方法です。

composer.jsonrequireに、Doctrine を追加しました。

    "require": {
        "php": ">=5.4.0",
        "laravel/framework": "4.1.*",
        "doctrine/dbal": "~2.3" // <--- 追加!
    },

Heroku にデプロイすると、バッチリ動きました!Herokuさん、疑ってゴメン。

実際にデプロイしたものが下記です。

http://laravel-table-admin.herokuapp.com/crud/classes

コードは、Github で公開しています。Heroku でも Pagodabox でもデプロイできているので、両 PaaS にPHPアプリケーションをデプロイする際は参考にどうぞ。

https://github.com/shin1x1/laravel-table-admin-example

さいごに

まあ分かってしまえば、単純というよくある話です。

Heroku が Composer を拡張しているかどうかは分かりませんが、ドキュメントには、composer 実行前に self-update しているという記述もあるので、Composer は標準のもので、別途compoer.jsonを見てランタイムを決定するシステムがあるのかもしれません。

あと、夜中に躓いたら、さっさと寝るということですね。睡眠大事。

追記

ラインタイムや拡張を実際に指定する処理は、PHP の buildpack に記述がありました。@iakio さん、ありがとうございました!

  • コメント (Close): 0
  • トラックバック (Close): 0

Home

検索
フィード
メタ情報

Return to page top