PHP Composer を高速化する方法を簡単にまとめました

便利ですが、重たい PHP のパッケージマネージャの Composer を、とても早くできる方法をまとめました。

結論から言うと、ご紹介するコマンドを2回たたくだけで、次のことが可能になります。

・Composer の通常通信: 地球220周分の通信 -> 2周分までにおさえられる
・Composer の通常通信: シングルスレッドの通信 -> プラグインで、並列ダウンロードできる

1. 日本にあるミラーサイトを以下のコマンドで有効化する

composer config -g repos.packagist composer https://packagist.jp


解除する場合

composer config -g --unset repos.packagist

2. 通信を curl に変更し、並列ダウンロードできるようにする

composer global require "hirak/prestissimo:^0.3"


解除する場合

composer global remove hirak/prestissimo

「PHPカンファレンス関西2016」で発表された資料の手順を抜粋し、最新化したものです(2017年1月現在)。


『Composerを速くするために必要だったもの』
https://speakerdeck.com/hirak/composer-keynote|

何をしているか、ざっくり説明します。

composer のリポジトリは、フランスにあります。
アジア圏は物理的に、約8,000km も離れています。
また、さまざまな通信的成約から、通常、地球220周分もの通信が行われるため遅くなっている、ということです。
そこで、このリポジトリのミラーサイトを日本に作ってくれたのが、資料の作成者である hirak さんです。
このミラーサイトを経由すれば、地球220周分→ 2周分までに物理的な距離が削減されます。

また、composer の通信はシングルスレッドなのですが、curl で並列ダウンロードさせるためのプラグインを作ってくれたのが、またまた hirak さんです。
GitHub でのスターは2300を超え、いまや世界の hirak と呼ばれているそうです。
気に入られたら、GitHubの https://github.com/hirak/prestissimo で star を押してあげましょう。
既に2400近いstarが集まっていて、PHP界ではかなり盛り上がっています。

昨年(2016年)のカンファレンスでこの資料があがってから、すごい、と感激したものの、なかなか実行にうつせませんでした。
あと、スライドで紹介されている、プラグイン導入のコマンドが現在は古くなっているので、更新しています。

ほぼPHPでGulpやGruntのようなタスクランナーがシンプルに自作できそうな話と、PHPタスクランナーを見つけた話

By: section215

今回は、サーバサイドのエンジニアとして、タスクランナーについて考えていたことをまとめてみました。
一時期、タスクランナーにはまったことがありました。
最初はGruntで、次はGulpでした。
どちらも素晴らしいのですが、少し不満もあったのです。

そもそもタスクランナーとは

まずタスクランナーについて。
これはコンパイルや、ファイルの結合、最適化、圧縮など、開発に伴う手続き(タスク)を自動化するツールです。

開発をする限り、どうしても発生する作業を省いてくれるわけです。
Web開発では、CSSのプリプロセッサのSASSのコンパイルだったり、スタイルシートやJavaScriptの結合、圧縮が主になります。

そのほか、PHPDocumentorだったり、APIの資料だったり、スタイルシートガイドという文書を作成することもできます。
こういうものが自動で作れると、チームでの作業がはかどります。
また、人間は忘れる生き物なので、未来への自分自身に向けての保険にもなります。

node.jsのライブラリはサーバサイドに比べるととにかく大きい

さて、本題です。
Gulpは、node.jsというフロントサイドのテクノロジーで動きます。
つまり、サーバサイドのPHPやRubyで作っていようが、「JavaScript」を書かないといけない訳です。

Gruntに比べると、Gulpのタスクは、jQueryのようなライブラリしかさわったことのない人間でも、理解できると思います。

さて、Gulpに慣れてくると、以下の問題に気付きました。

     

  • 基本的なタスクをそろえると、nodeのライブラリが100MBを優に超える
  • メインの言語とは関係のないところで結構注力しないといけない

PHPが好きな人は、コンパイルがなくて、どのプラットフォームでも導入でき、実行できる手軽さが気に入っていると思います。
そこに、タスクランナーです。

PHP、あるいはRubyで軽いアプリを頑張って作成しているのに、裏ではタスクランナーのファイルがどんどん巨大化しているのです。
アプリの一部として、なんだか気にくわない訳です。
どうでもいい人にはどうでもいいのでしょうが、ノートPCでも開発ができるようになった昨今、できるだけ軽い環境で作業したいものです。

そこで、探し回ることにしました。
PHPでタスクランナーを作れないか、と。
フレームワークのPhalconには、cssminやjsminという組み込み済みのアセットメソッドがあります。
しかし、これは毎回該当の画面にアクセスしなければ動かず、また、CSSやJS以外のものはできません。

他のフレームワークでも、似たり寄ったりのようです。
PHP(Laravel)製TaskRunner「Envoy」を試してみた

気になったのは「Robo」です。
まだ試してはいません。というのも、サンプルコードに載っていたのがコンパイル系ではなかったので。
また時間があれば試します。

PHPでもアセット作りはシンプルにできる

あとは自力で開拓するまで。
Packagistを漁ってみたところ、以下のツールを見つけました。

名前から分かると思いますが、その通りの機能を持つものです。
CSS、JSの圧縮、SASSのコンパイル、結合(concat)…。
Gulpの主力機能がみんなありますね。

ちなみに、すべてcomposerのコマンドひとつでインストールできる手軽さです。
最後のだけ、JSONで結合するファイルを記述します。

試したところ、上記3つは、指定したファイルを引数にして、返り値にコンパイルした文字列を返すものです。
シンプルです。
フォルダ内のファイルリストを抽出して、1件ずつ回す処理を書くと、いい感じになります。

問題は「監視」

さて、タスクランナーなので、ファイル監視が必要です。
これは、ファイルを編集した時、自動的にタスクを実行する機能です。
これが意外に面倒で、ざっと調べると、コマンドプロンプト、PowerShellなどのパワーを借りる必要があるようです。

By: Robert

もっとシンプルにしたい、と考えてみました。

そもそもnode.jsのGulpにファイル監視機能があるなら、node.jsでファイル監視の機能だけ提供しているライブラリがあるのでは? と気づきました。

node.jsのライブラリを探すと、やっぱりありました。
Chokidar」です。
これは、約1.3MBほど。これ単体で動くならまだ許せる範囲です。

修正を検知した瞬間、「php task.php」をたたかせると、PHPファイルを実行させることができました。
ただ、ワンテンポ遅れて動くようです。ファイルの指定の仕方はまだ調査が必要のようです。

真打登場 taskphp

さて、ここまで記事を書いてきて、さらに調査を進めると、Symphonyコンポーネントで、PHPのみで記述できるタスクランナーが、とうとう見つかりました。

taskphp

サンプルコードを見ればわかる通り、Gulpに大変近い書き方です。
ここに、本記事で見つかったライブラリを登録すれば、Gulpそのものの働きをしてくれそうです。

今後は、軽い案件は、composer でライブラリを入れて、Chokidarで高速かつ軽量に対応できそうです。
中規模の案件でも、taskphp で十分いけそうです。

きっとできる、PHPなら

最後に。
フロント側のテクノロジーはそれなりに素晴らしいので、これも時代の流れかと仕方なしに習得している感があります。
つまり、サーバサイドのエンジニアとして、PHPやRuby、Pythonを使っているのに、node.jsにここまで頭を切り替える必要があるのかな、という疑問です。
AngularJSや、PugのようなHTMLのコンパイラにふれると、静的コンテンツで無理やり動的な動きを実装している、という印象は、サーバサイドの人間なら誰でも感じてしまうのではないでしょうか。

要は、使いどころと、実際の仕事としてどれだけのものがあるか、で考えればいいのかなと、この記事を書いてみて、結論が出ました。

モバイル向けのアプリをMonacaなどで作りたければ、フロントはnode系で作り、バックエンドのAPIはサーバサイドで作ればいい。

また、実際の仕事として、ウェブアプリ開発では、別にサーバサイドの技術がすたれているわけでも何でもない状況なわけです。

そして、PHPなら何でもできるよ、という自信を今回得られることができました。
node.jsすごいね。でも、同じことはPHPなら(少なくとも、もっと手軽な大きさで)実現できるよ、と。

つくづく、PHPを選んで良かったなと思います。

Notepad++ で tail -f する方法

※ (2016.12.11更新) v7.2.2 になって、「表示」メニューに「ファイル監視 (tail -f)」が追加されました。
以下の記事は、標準メニューにファイル監視がないバージョンでの対応方法になります。


Heroku のログをローカルでモニタリングするサンプルです。

プラグイン「Document Monitor」をインストール

  • 「プラグイン」メニューより、「Plugin Manager」> 「Show
    Plugin Manager」でプラグイン・マネージャを開く
  • 「Availabel」タブより、「Document Monitor」にチェックして、右下の「Install」ボタンをクリック

使い方

  • Notepad++ のルートを開き、ログを書き込むファイルを設置する(C:\Notepad++Portable\logs.txt)
  • tail コマンドで出力先のログファイルを指定する(heroku logs –tail –app hoge-manager-stg > C:\Notepad++Portable\logs.txt)
  • プラグイン > [Document Monitor] -> start to monitor で開始

Notepad++ のルート直下にファイルを置くというのがポイントです。
他の場所においても、モニタリングしてもらえませんので、注意して下さい。

[PHP x Ajax] 非同期でセッションを複数処理する場合の注意点

発生した問題点:

  • 時間のかかる非同期処理を実行 -> その処理が終了する前に画面遷移
  • 画面遷移後、セッションを更新していると、前の画面の処理が終わった瞬間、セッション情報が古くなってエラーが発生
    • どうやら、非同期処理で実行した処理が、バックで動き続け、画面遷移した後で終了したタイミングで上書きされる模様

セッションを使わずに処理を行うようにしたりとか、色々試しましたが、根本的な原因は「セッション処理は常に1つずつ」行われ、実行中はロックされるということ。

下記の記事が参考になりました。ありがとうございました。

「【ajax】複数のajax送信を同時に行ってPHPのセッションを扱うときの注意点」

「phpでajaxとsessionを使う時の注意点:なんとなしの日記」

対応策

「session_write_close」を使うこと。

  • 現在のセッションを終了し、セッションデータを書き込む
  • セッションは同時書き込みを防ぐため、スクリプトの終了まではロックされる
    • セッションの処理ができるのは、常に1つだけ
  • セッションの変更後にすぐにセッションを終了することで、ロック待ちによる遅延を防ぐことができる

過去に非同期で複数の処理を取得しようとして、遅延が発生していた件が思い当たりました…。これでしたか……。
非同期なのに、どうして遅くなるのか不思議でした。

問題のスクリプトのエラーは発生しなくなりました。
原因が分かりましたので、今後は積極的に利用していこうと思います。

PHP 配列を初期化しながらセットすると Undefined offset になる事例

PHP x Phalcon で遭遇した事例です。
Postgres のストアドクロシージャの処理をPHPに移植する案件ではまりました。

こんな環境も珍しいでしょうが…。

配列を初期化したあと、指定した回数回して、自分自身に値を加算していきます。

$can = [];
$tel = [];
$shop = [];

foreach ($result as $key => $val) {
    for ($i = 0; $i < 48; $i++) {
        $can[$i] = $can[$i] +$val[$i];
        $tel[$i] = $can[$i] +$val[$i];
        $shop[$i] = $shop[$i] +$val[$i];
    }
}

すると、Notice: Undefined offset: 0(インデックスの数) と出力されます。

Postgres のストアドでは、上のような書き方になって動いていたのですが、
PHPで動かすと、インデックスがまるでききません。

つまり、「まだ値が確定していない配列に対し、キーで参照するのはおかしい」ということですね。

解決策は、事前にインデックスをちゃんとセットすることです。

for ($cnt = 0; $cnt < 48; $cnt++) {
    $can[] = '';
    $tel[] = '';
    $shop[] = '';
}

この後、加算処理を入れれば動きます。

PHPで最初から書けばこんなことにならないと思いますが、
他人の書いたコードを適用したり、多言語から移植とかイレギュラーなことをしたら遭遇するかもです。
怪しいコードは、1行ずつテスト、ですね。
参考になりましたら幸いです。
以上です。