PHPフレームワークのベンチマーク一覧の記事を拝見し、
Laravel5が遅いという結果が出てしまいちょっとへこみました。
ま、まぁハロワの早さがフレームワークの優劣じゃないし(震え声
ハロワ程度でもちょっとメモリとか多く使っちゃうだけだし(震え声
などと色々理由を付けて自分の涙を無かったことにしています。

一口に速度といっても2つの指標があって、実行速度と開発速度があって
Laravelは開発速度に重きを置かれているということなので、
こういう差がでちゃうのも仕方ないんじゃないかなーと思っています。

ちなみに、今度日本で初めてLaravelの本が出るらしいですね。ちょっと気になっています。
Laravelエキスパート養成読本[モダンなPHP開発を実現するノウハウ満載!] (Software Design plus)

さて本題に戻って、Laravelでのバッチ開発まわりに関して、
公式ドキュメントを読んでも、どうも的を射なかったのでまとめてみます。

目標

Laravelフレームワークを使用したバッチ処理の開発、cronスケジューリング

主要技術・環境

Laravel5

実装

バッチの実装

まずはバッチクラスの作成をartisanコマンドにて行います。

1
2
$ php artisan make:console TestCommand --command='batchtest'
Console command created successfully.

クラス定義が簡単でいつも助かります。
上記コマンドを叩くことで、 TestCommand というクラスファイルが自動で作成され、
batchtest というコマンドが用意され、 $ php artisan batchtest で実行できるようになります。

さて、ファイルができる場所ですが

filedir

project/app/Console/Commands/TestCommand.php にできます。
早速、中身を確認してみましょう。

001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
073
074
075
076
077
078
079
080
081
082
083
084
085
086
087
088
089
090
091
092
093
094
095
096
097
098
099
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
<!--?php namespace AppConsoleCommands;
  
use IlluminateConsoleCommand;
use SymfonyComponentConsoleInputInputOption;
use SymfonyComponentConsoleInputInputArgument;
  
class TestCommand extends Command {
  
/**
 * The console command name.
 *
 * @var string
 */
protected $name = 'batchtest';
  
/**
 * The console command description.
 *
 * @var string
 */
protected $description = 'Command description.';
  
/**
 * Create a new command instance.
 *
 * @return void
 */
public function __construct()
{
    parent::__construct();
}
  
/**
 * Execute the console command.
 *
 * @return mixed
 */
public function fire()
{
    //
}
  
/**
 * Get the console command arguments.
 *
 * @return array
 */
protected function getArguments()
{
    return [
        ['example', InputArgument::REQUIRED, 'An example argument.'],
    ];
}
  
/**
 * Get the console command options.
 *
 * @return array
 */
protected function getOptions()
{
    return [
        ['example', null, InputOption::VALUE_OPTIONAL, 'An example option.', null],
    ];
}
  
}
</pre-->
<p>見た通りな感じですが、 fire() がメインの動作関数ですね。<br>
<code>fire()</code> を編集してみましょう。とりあえず実行確認のechoしてみます。</p>
<pre class="brush: php; title: ; notranslate" title="">    public function fire()
    {
        echo 'コニチワ';
    }
</pre>
<p>コニチワします。<br>
では実行してみましょう。</p>
<pre class="brush: bash">$ php artisan batchtest
exception 'InvalidArgumentException' with message 'Command "batchtest" is not defined.' in ~~~
</pre>
<h5>怒られた!</h5>
<p>コマンドを登録しないといけないようで。<br>
<code>app/Console/Kernel.php</code> に、下記の通りコマンドクラス定義を追加する必要があります。<br>
ここまで<code>artisan</code>コマンドで追加してくれてもいいと思うのだけどなぁ。</p>
<pre class="brush: bash; title: ; notranslate" title="">protected $commands = [
    'AppConsoleCommandsInspireCommand',
    'AppConsoleCommandsTestCommand' // 追加
];
</pre>
<p><code>TestCommand</code> クラスを呼び出すよう定義して <code>batchtest</code> コマンドを有効化します。<br>
で、再度実行してみます。</p>
<pre class="brush: bash; title: ; notranslate" title="">$ php artisan batchtest
exception 'RuntimeException' with message 'Not enough arguments.' in ~~~
</pre>
<h5>怒られた!</h5>
<p><code>getArguments()</code> がデフォルトでは引数を一つ受けないとエラーを吐くようになっているようです。<br>
引数を取る必要がなければ関数まるごと削除してしまって良いようです。<br>
とりあえず適当な引数をつけて実行してみましょう。</p>
<pre class="brush: bash">$ php artisan batchtest "example"
コニチワ
</pre>
<h5>コニチワ!</h5>
<h4>引数を受けとりたい</h4>
<p>引数を受けて処理を分けるというのも多くあるので、そこまで触ってみます。<br>
そもそも初期設定の下記はどういう意味かというと、</p>
<pre class="brush: bash; title: ; notranslate" title="">    protected function getArguments()
    {
        return [
            ['example', InputArgument::REQUIRED, 'An example argument.'], // 一つの引数を受け取る
            // ['プログラムで受ける変数名', '必須入力か否か', '引数の説明']
        ];
    }
</pre>
<p><code>getArguments()</code> の返り値配列の要素数が引数の数。<br>
中の配列が「変数名、必須引数か、引数の説明」となっているので、<br>
初期設定では、「引数を一つ必須入力、受け取ったら変数名を’example’とする」みたいな感じです。</p>
<p>デフォルト引数のような使い方をしたい場合は、 <code>InputArgument::REQUIRED</code> を <code>null</code> とすればいいようです。</p>
<pre class="brush: bash">        return [
            ['lang', null, 'choose language. default="ja"],
        ];
</pre>
<p>これで、「引数一つ自由入力、受け取ったら変数名を<code>’lang’</code>とする」という感じでしょうか。<br>
で、どうやって引数を受け取るかですが、 <code>fire()</code> 内で <code>$this->argument('変数名')</code> で使えるようです。<br>
<code>__constract()</code> 内で受け取れないのがちょっと勿体無い感じがしますねぇ。<br>
ということで、処理分けは以下のようにできるようですね。</p>
<pre class="brush: bash">public function fire()
    {
        $lang = empty($this->argument('lang')) ? 'ja' : $this->argument('lang');
        switch($lang){
            case 'ja':
                echo "コニチワn"; break;
            case 'us':
                echo "ハローn"; break;
            default:
            ~~
</pre>
<p>動かしてみましょう。</p>
<pre class="brush: bash; title: ; notranslate" title="">$ php artisan batchtest
コニチワ<p></p>
 
<p>$ php artisan batchtest us
ハロー</p>
 
<p>$ php artisan batchtest hoge
สวัสดี
</p></pre>
<h5>สวัสดี!!</h5>
<p><code>empty()</code> じゃなくて <code>strlen()==0</code> で受けるべきかな?まあ用途によって。</p>
<p>cron設定</p>
<p>バッチを作成するたびにサーバにSSHログインしてcronの設定をしないといけないのは面倒ですね。<br>
複数台全てにcrontab設定するのは骨が折れる。<br>
Laravelでは、ソースレベルでコマンド実行のスケジューリングを設定できて素敵です。<br>
crontabに下記を設定します。</p>
<pre class="brush: bash">* * * * * php /path/to/project/artisan schedule:run 1>> /dev/null 2>&1
</pre>
<p>すると、毎分バッチ管理スケジューラを起動して、設定にマッチするものを実行するという感じ。<br>
公式ドキュメントには「これ以上簡単にできません!」との記述が。</p>
<h5>多分これが一番簡単だと思います。</h5>
<pre class="brush: bash">    protected function schedule(Schedule $schedule)
    {
        $schedule->command('inspire')
                 ->hourly();
        $schedule->command('batchtest')->dailyAt('7:00'); // 追加
    }
</pre>
<p>これだけで毎朝7時にコニチワできます。<br>
引数をつけたい場合は <code>command('batchtest us')</code> とすればいいだけですね。<br>
バッチが多くなればなるほど、管理の容易さが感じられそう。</p>
<h3>結果・考察</h3>
<p>毎朝7時にコニチワする定期実行バッチができました。</p>
<p>同じプログラムを複数サーバにデプロイする時は、<br>
サーバのホスト名を見て、バッチサーバでだけ実行するとか、web01だけで実行するなんて事も可能ですね。<br>
PHP処理ならではの細かい設定を入れられて管理のしやすいcron、面白いです。</p>
<script type="text/javascript">window.NREUM||(NREUM={});NREUM.info={"beacon":"bam.nr-data.net","licenseKey":"NRJS-969e521f365eb8162cd","applicationID":"1072048185","transactionName":"ZFEGZBZZD0QCWxAPV10bJVMQUQ5ZTEsNCF9fUUlAC0sV","queueTime":0,"applicationTime":1432,"atts":"SBYFEl5DHEo=","errorBeacon":"bam.nr-data.net","agent":""}</script>