PHPMatsuri2012 (前夜編)

こんばんは、イケメンじゃなかったほうの田中です。

PHPMatsuriでした。行きましたよ。去年はホーム大阪での開催にもかかわらず、運動会事情でホテル代含みで全額払って1日で帰るという悔しい思いをしたので、今年はそのリベンジを果たしにいざ福岡の地へ。

あ、普通にためになるレポートはみなさん素晴らしいエントリを書いてくださっているので、togatterを参照する (http://togetter.com/li/402628) なりするといいと思います。これはあくまで個人的な日記です。すごく個人的にPHPコミュニティスゲェなことを書きたいと思います。

PHPはロックですね。

まず今年の開催場所ですよ。福岡です。博多です。観光地じゃないですか。もうこれ遊ぶ気満々じゃないですか。そして会場は

Ruby・コンテンツ産業振興センター

これはロックですよね。ボーダレスですね。

でまあ、某アシアルの社員でおかしなTシャツを着ている人が、前日に同じ会場で何か勉強会をやってて懇親会があるよと言うので、そんじゃあまあ景気付けにそれを理由に前日軽く飲むかーと思って有給使って前泊で予定しました。

Google Maps カタカタ Ruby何とかセンター カタカタ...

「ここかー、駅から5分ってそれどこの不動産レートですかって話よねー、まあ歩いて行けないこともない距離だなー」

「近くのホテルは...おお、ここ近くて安い、ここにしよう」ポチっと

と、その直後、なにかおかしいことに気づいた。あれ? 東側? 西側じゃないの?

なんと、博多にはRubyのコンテンツのセンター が2つあったのです!

バッチリ遠い方の近くに宿を取ってしまいました。皆さん、博多駅の近くで勉強会があるときは気をつけましょう。Rubyセンターは2つあります。片方は総合庁舎内の施設なのでGoogleの地図に出て来ません。


まあ仕方がないのでまずはその遠い宿へ。新しいMacbookを抱えて新大阪駅から新幹線に乗る前に本屋に寄りました。暇だったので、みんなこの本を買って行きましょうってツイートするときの写真を撮るために。

で、ふとTwitterを開くと、ちょうど公式アカウントからの告知が!

そのとき、本屋の平積み台の一番目立つところにあったのはまさにあの本...

もうこんなの、やるしかないじゃないですか。

エントリー!

お褒めの言葉、ありがとうございます。


さてさて、ゆるゆると新幹線移動っと...移動しながら作業したりまとめたりできるからねー。
と、思っていたのですが、そこでまた大きなミスを犯していたことに気づきました。

大阪から西に向かう新幹線には電波が届かない!

大坂〜東京間の感覚でいたらダメなんですね。新神戸から先、駅以外ほぼトンネルor人が住んでない場所。ほとんど都市部を通りません。ああっ、岡山...ツーツーツー、広島なら...ツーツーツー、そんなこんなで、電波が生きているわずかな隙間を見つけては、


「40秒で git push しな!」

って感じの状態でした。

九州方面へ行かれる方は、中国地方をナメてはいけません。ソフトバンクやイー・モバイルではあの地形には太刀打ちできないと、肝に銘じておいたほうがいいでしょう。


博多に到着、バス乗り間違えて昼間の歓楽街を歩いたり、Macbook Air を持って行ったらホテルのインターネット無料サービスが有線オンリーだったり、なんてトラブルもありながら、ところでアシアルさん、何時からだろう? って聞いてみたら、ぜんぜん最初から参加できそうな時間じゃないですか。

「ATNDで受け付けてますよ」

はい、開始1.5時間前にエントリー。

そうそう、Monacaは思ったよりずっといい開発環境でした。Webブラウザで動くIDEがかっこいいのと、実機テストにフルビルドが要らないのが特徴の、最初っからサーバ側ビルドを指向したPhoneGapって感じでした。告知告知。おかしなTシャツの人さん、ワークショップのデモで起こるバグはきっとnullチェックが原因だよって指摘したりして遊びました。

というわけで、いぇーい、前日から懇親会だー!
まあ、このあと軽く福岡の人と飲んで今夜はぐっすり... と、そこへ。

「田中さん田中さん、僕ですよ、わかりますか」

と、背の高い人とwidthの大きい人と半袖の人と物静かな外人が... えーっと、どっかで会ったことありますよね、そうですね、そりゃそうですよ、去年のPHPMatsuriのスタッフですよ。

なぜか、HTML5なスマホアプリの懇親会にPHPerの島ができました。まあそこまではよかった。

次に、PHPカンファレンス関西で5分で3回同じLTをした伝説のあの人物が合流するわけですよ。まだまあ、それはいいですよ。

とある猫のアイコンの人がその合流の流れをTwitterで察知して、いいなあ行こうかなって言います。ちょっとそれに気づくのが遅れたわけですよ。気づいたらもう、リプする前に、すでに来ちゃってるわけですよ。

しかも、ビール大好きなあのCakePHPの外人を連れて。

「いや〜、なんか見たことある外人が街を歩いてたから」

たいへんなことになってきました。

終電が近づいて地元の人が徐々に帰っていきますね。で、前泊してるPHPerは帰らなくてもいいわけですね。残ってるメンツがほぼ福岡以外のPHPerなわけです。さらに、店を出たらいつの間にか、海外からのゲスト参加のCakePHPコア開発者がもう一人増えてるんですよ。

前日からどんだけリッチな交流会ですかと。

二次会行きますね。完全に前夜祭ですね。残った焼酎ボトルとかテイクアウトしてますね。ロックすぎますね。

さらにさらに、まだ残ってくれてる貴重な地元の方に超美味いラーメン屋を教えてもらって、三次会まで行きます。時間は3:00AM。一部の人はもう一軒ラーメン屋行ったそうですが、おかしなことに、遠くなってしまったはずの自分のホテルの近くまで進出してきてたので、僕はホテルに戻りました。

レガシーコードのダウンロードと、BEAR.Sundayのmatsuriブランチのクローンをしなければなりません。

ちなみに、まだMatsuriは始まっていません。

始まる前からなんだこの濃さは。


三次会までいたのは、ある意味個人的には正解でした。そこで神レベルの豚骨に出会いましたからね。もうこれで、博多でやるべきマイミッションがひとつ達成されました。
まあ、このラーメン屋が、後々いろいろ重要になってきますが...

このあたりで、いったんエントリを分けることにしましょう。本編に続く。

HomebrewでPHP環境 現時点でのまとめ

MacでHomebrewを使ってPHPの開発環境を作るまとめです。

HomebrewはMacPortsより圧倒的にコンパクトなのがメリットです。MacPortsPHPをインストールすると、/opt/localに、Apacheを含め、すごい量のパッケージをインストールされます。PHPのビルドにApacheのライブラリが必要で、さらに、Apacheのビルドには...という具合。これだと、容量あたりの単価がかかるSSD搭載のMac bookがかわいそうですね。HomebrewのPHPは、MacOSApacheがあるのを知っているので、依存が浅くて軽いです。

MAMP.appがあるじゃないかという人はちょっと待った。あのパッケージ構造、httpd.confとphp.iniとmy.iniがどこにあるかすごくわかりにくいんですよね。そのうえ、使っている拡張の最新バージョン追従が個別にできないのは辛いです。

何よりHomebrewがいいのは、php54とphp53という個別のパッケージがあること。FuelPHPの仕事とBEAR.Sundayの趣味プロを同時にやりたいというとき、サクッと切り替えたり、php53を使っているときにphp54-xdebugのアップデートをしたり。

じゃあ、やり方いきますよ。

まずHomebrewのインストール

>Homebrew — MacPorts driving you to drink? Try Homebrew!

$ ruby -e "$(curl -fsSkL raw.github.com/mxcl/homebrew/go)"

/usr/local/binにbrewコマンドができるので、シェルでパスを通しておきましょう。パッケージに含まれるコマンドはここに入ってきます。

うまくいったか環境チェックするにはこう。

$ brew doctor

あ、ちなみに最新のXCodeが要るのでMac AppStoreで調達しておいてくださいね。

実はMacについてくるApacheにはPHP5.3が付いてきます。Homebrewは「Macに最初から入っているものは含まない」というポリシーを守っていて、PHPは既存ソフト扱いなんだそうです。でも、アップデートされないわ、バージョン固定だわ、Xdebugは使えないわ、MySQLのドライバ入ってないわ、なんてPHPは使いたくないですよね。

そんなある日(2012年の4月ごろだったかな)、HomebrewにTapという機能が導入されました。外部のFormula(パッケージの定義)集を追加/管理するコマンドです。

https://github.com/mxcl/homebrew/wiki/Homebrew-0.9

これでオリジナルのFormulaと混ぜることなく、GitHubにある外部のFormulaセットを追加することが可能になります。たったこれだけ。

$ brew tap homebrew/dupes
$ brew tap josegonzalez/homebrew-php

削除は brew untap コマンドです。

事前に homebrew/dupes を追加しているのは、その一部に homebrew-php が依存しているためです。

さてこれで準備OKなのでお待ちかねPHPをインストール。

まずはどんなインストールオプションがあるかを確認します。

$ brew options php53
--without-bz2
	Build without bz2 support
--with-tidy
	Include Tidy support
--with-fpm
	Enable building of the fpm SAPI executable (implies --without-apache)
--with-cgi
	Enable building of the CGI executable (implies --without-apache)
--with-gmp
	Include GMP support
--with-intl
	Include internationalization support
--with-unixodbc
	Include unixODBC support
--without-pear
	Build without PEAR
--with-mssql
	Include MSSQL-DB support
--with-mysql
	Include MySQL support
--with-suhosin
	Include Suhosin patch
--with-mariadb
	Include MariaDB support
--32-bit
	Build 32-bit only.
--with-homebrew-openssl
	Include OpenSSL support via Homebrew
--with-pgsql
	Include PostgreSQL support
--with-imap
	Include IMAP extension
--without-apache
	Build without shared Apache 2.0 Handler module
--with-libmysql
	Include (old-style) libmysql support

intlがないとSymfonyに怒られるのでオン、あと、MySQLPostgreSQLのドライバも入れましょう。

$ brew install php53 --with-intl --with-mysql --with-pgsql

まだMySQLPostgreSQLをインストールしていない場合、MySQLPostgreSQLのインストールが始まります。分けてやってもいいのですが、記事を書くのが面倒なので依存を一気に入れちゃおうと...

やってみたらドライバだけはインストールされましたが、MySQL等の本体は別途インストールしないとだめでした。勝手に依存を入れるわけではなくなったようです。

インストール中にいろいろメッセージが出てきますが、まあ、最初はスルーしておきましょう。最後に出てくるPHPの設定ガイドだけしっかり見て下さい。

For 10.5 and Apache:
    Apache needs to run in 32-bit mode. You can either force Apache to start
    in 32-bit mode or you can thin the Apache executable.

To enable PHP in Apache add the following to httpd.conf and restart Apache:
    LoadModule php5_module    /usr/local/Cellar/php53/5.3.16/libexec/apache2/libphp5.so

The php.ini file can be found in:
    /usr/local/etc/php/5.3/php.ini

☆☆☆☆ PEAR ☆☆☆☆

If pear complains about permissions, 'Fix' the default PEAR permissions and config:
    chmod -R ug+w /usr/local/Cellar/php53/5.3.16/lib/php
    pear config-set php_ini /usr/local/etc/php/5.3/php.ini

☆☆☆☆ Extensions ☆☆☆☆

If you are having issues with custom extension compiling, ensure that this php is
in your PATH:
    PATH="$(brew --prefix josegonzalez/php/php53)/bin:$PATH"

Extensions will never be compiled against this homebrew-php PHP. Please install them
using --with-homebrew-php to enable compiling against this php.

☆☆☆☆ FPM ☆☆☆☆

If you have installed the formula with --with-fpm, to launch php-fpm on startup:
    * If this is your first install:
        mkdir -p ~/Library/LaunchAgents
        cp /usr/local/Cellar/php53/5.3.16/homebrew-php.josegonzalez.php53.plist ~/Library/LaunchAgents/
        launchctl load -w ~/Library/LaunchAgents/homebrew-php.josegonzalez.php53.plist

    * If this is an upgrade and you already have the homebrew-php.josegonzalez.php53.plist loaded:
        launchctl unload -w ~/Library/LaunchAgents/homebrew-php.josegonzalez.php53.plist
        cp /usr/local/Cellar/php53/5.3.16/homebrew-php.josegonzalez.php53.plist ~/Library/LaunchAgents/
        launchctl load -w ~/Library/LaunchAgents/homebrew-php.josegonzalez.php53.plist

Mountain Lion comes with php-fpm pre-installed, to ensure you are using the brew version you need to make sure /usr/local/sbin is before /usr/sbin in your PATH:

  PATH="/usr/local/sbin:$PATH"

You may also need to edit the plist to use the correct "UserName".

Please note that the plist was called 'org.php-fpm.plist' in old versions
of this formula.

php.ini は /usr/local/etc/php/5.3/php.ini です。5.4 だとこれが php/5.4/php.ini になります。

Apache にロードするには /etc/apache2/httpd.conf あたりにこんな感じで追加します。Apacheは homebrew/dups でビルドしてもいいですね。今は簡単に MacOS の標準に入れておきましょう。

#LoadModule php5_module libexec/apache2/libphp5.so
LoadModule php5_module    /usr/local/Cellar/php53/5.3.16/libexec/apache2/libphp5.so

PEARを使うために、手動でこんな操作が必要らしいのでやっておきましょう。パーミッションが書き込みできないようになってて、pear がうまくいかないのです。忘れるとマジでハマります。

$ chmod -R ug+w /usr/local/Cellar/php53/5.3.16/lib/php
$ pear config-set php_ini /usr/local/etc/php/5.3/php.ini

え、こんなの全部憶えられない? って、エディタにコピーなんかしとかなくても大丈夫ですよ。コマンドでもう一度表示させることができるので、設定が済んだら忘れていいですよ。

$ brew info php53

ほら。

これで、MySQLPostgreSQLの設定も確認できます。一括でインストールして読み飛ばしてもいいよというのはそういう意味。

$ brew info mysql
$ brew info postgresql

Hello Worldやるぶんには使わないので、あとでこれ見て勝手にやっといてください。

$ php -r 'echo "Hello World\n";'

はいこんにちは。

あと、開発するなら必須な拡張をいくつかインストール。何はなくとも、XdebugとAPCは要りますよね。

$ brew install php53-xdebug --with-homebrew-php
$ brew install php53-apc --with-homebrew-php

おしりの --with-homebrew-php がポイントです。これを付けないと、MacOSのデフォルトのPHPをリンクしてしまったり、5.4用の拡張なのにカレントの5.3をリンクしたり、という現象が起こりかねません。これを指定することで、必ず、Homebrewのphp53をリンクするようになります。(php-build等で勝手インストールしたランタイムとリンクしたい人のために、デフォルトは遠慮してるそうです)

追記ここから

$ brew install php53-xdebug
$ brew install php53-apc

2012-10-08から、オプションの指定が逆になったようです。--without-homebrew-php で、homebrewのPHPをできるだけ避けてビルドするようにし、何も指定しなければhomebrewの対応するバージョンのPHPを使うのがデフォルトになっています。なのでオプションに注意しなくてもOKです。

ここまで

あ、ちなみにこれ、今日やっと正常に動作したホットな機能です。ここ修正されたのが、このエントリを書いてる動機です。

https://github.com/josegonzalez/homebrew-php/issues/151
https://github.com/josegonzalez/homebrew-php/issues/297

XdebugとAPCのインストールが済むと、便利なことに、/usr/local/etc/php/5.3/conf.d/ext-xdebug.ini と /usr/local/etc/php/5.3/conf.d/ext-apc.ini ができました。とりあえず初期設定のまま使うぶんには、 php.ini の修正はしなくていいです。

ふー、あともう一歩、PEARで開発に必須なものを入れます。

$ pear config-set auto_discover 1
$ pear install pear.phpunit.de/PHPUnit
$ pear install PhpDocumentor
$ pear install pear.phing.info/phing

まあこれぐらいあればまずはいいでしょう。パーミッションでハマらないように。

PEARでツールをインストールしたときは、もうひとつハマりどころがあります。インストールが成功してもすぐにはコマンドが使えないんですよね。Homebrewでインストールしたコマンドの正体は、/usr/local/binの中に置かれたシンボリックリンクなんですが、PEARを初めて使う前にもう、それ済んじゃってますよね。というわけで、シンボリックリンクを作り直します。

$ brew unlink php53
Unlinking /usr/local/Cellar/php53/5.3.16... ?? links removed
$ brew link php53
Linking /usr/local/Cellar/php53/5.3.16... ?? symlinks created

完了。phpunit も phing も使えるようになりました。

じゃあ、php54 も同じ要領でインストールしましょう。できますよね、3が4になるだけですよ。

〜時間がかかるのでこちらに出来上がったものがございます〜

5.3と5.4の切り替えは、Cellerに直接パスを通してやるのもいいけど、

# export PATH="$(brew --prefix josegonzalez/php/php53)/bin:$PATH"
export PATH="$(brew --prefix josegonzalez/php/php54)/bin:$PATH"

Homebrewのbinにあるリンクを再設定する方法だと、 .bash_profile を編集する必要もなくてラクラクです。

5.4 -> 5.3

$ brew unlink php54
$ brew link php53

5.3 -> 5.4

$ brew unlink php53
$ brew link php54

仕事中にこっそり裏でビルトインサーバとかBEAR.Sundayとかぐへへ...

そうそう、定期的にパッケージの更新は、やったほうがいいですよ。

$ brew update
$ brew outdated
$ brew upgrade

$ brew unlink php53; brew link php54
$ pear list-upgrades
$ pear upgrade

$ brew unlink php54; brew link php53
$ pear list-upgrades
$ pear upgrade

MacのCheatSheetが素晴らしかった

http://cheatsheetapp.com/CheatSheet/

これ起動しておくと、commandキーを押して「あれ? あのショートカットキーなんだっけ?」って思ってると、こんなのが出てくれます。

これ、Mac OS 標準のアプリケーションだけでなく、ショートカットの登録状況を見て、どんなアプリでもショートカットの一覧を出してくれるんですね。ツールバーボタンは少なくて初心者に優しいけど、上級者には全部ショートカットを覚えろとなかなか厳しい、そんな感じのMacの習慣に慣れない人にはすごくオススメ。

「はじめてのフレームワークとしてのFuelPHP」書評

ご無沙汰しております。ものっそ久しぶりに書きます。

著者様から献本頂いて、達人出版会発行の「はじめてのフレームワークとしてのFuelPHP」読みました。EPUBをダウンロードするやつです。

http://tatsu-zine.com/images/books/37/cover_s.jpg

http://tatsu-zine.com/books/fuelphp1st

ただのFuelPHPのテクニック本だと思ったら大間違い、FuelPHPはむしろPHPフレームワークのわかりやすい一例として取り上げましたという印象で、この本の本質は、今どきPHPで開発するってのは、これぐらいの基準ラインに乗ってるよ、というのが一気にわかる本でした。

  • 自分のローカルホストにきっちり開発環境作る
  • OSSコミュニティへのURLリンクをしっかり持つ
  • 自分が使っているOSのコマンドラインを押さえよう
  • どれぐらいWeb開発用語の知識を持つべきか体で知ろう
  • フレームワークと呼ばれるものがおよそどんな機能を持つのか
  • Webアプリケーションのセキュリティは初心者向けでも案外レベル高いぞ
  • 自動テスト自動テスト自動テスト、ロジックは徹底して自動テスト
  • そしてフレームワークを盲信しないこと(^^;

ざっくりこんな内容です。えと、FuelPHPはどこに? いや大丈夫、表向きはFuelPHPとEclipseのチュートリアル形式で学びながらなので、つかみはOK、あとは日本語ドキュメントがあるからもう大丈夫でしょって感じにはなりますよ。

不必要に長い説明はなく、これやる、これやる、これやる、と、淡々と進みます。長ったらしい説明を読んでいちいち良し悪しを考えたりしないで、まず言われたとおりに受け取る、というふうに読めるので、用語ですごく詰まる人でないかぎり、サクサクいけます。本だけでは説明不足に感じるところがあっても、実はキーワードだけはしっかり登場してるので、それマークしておいて、あとで検索する学び方もいいですね。Web時代ですね。電子書籍っぽいですね。

本書の流れの中でとくに好感を持てたのが「モデル」の扱いです。機能を試している間はアプリケーションのモデルが存在しないので、びっくりするぐらいコントローラに実装が書かれます。うーん、MVCって最初に言ってたのに大丈夫かなと思っていると、後半、アプリケーションに目的ができてきた瞬間から、機能的なサービスをモデル層に移して単体テスト、という怒涛の流れに入っていき、データベースの便利CRUDもORマッピング(というかかなりActiveRecordっぽいけど)の使い方も、最後の章でようやく登場します。

はいこれ、なんてすばらしいんでしょう。

WebアプリケーションフレームワークRails以降、ActiveRecordCRUDが目立ちすぎました。それで何が起こったかというと、データベースに保存できるActiveRecordを最初に「モデル」と呼び、まずその操作をマスターするような学習フローが流行ったんですよね。最初にそこ叩き込まれるから、初学者が「モデル」=「DBの行」って思っちゃう。それで、「いろんな処理」=「ロジック」=「コントローラ」って印象になってしまう。モデルがひとつの行を表さないといけないから、複数のオブジェクトが対等に処理されるべきロジックを特定のモデルクラスに所属させたくない→コントローラ? 違いますよね。

モデルはアプリケーションの目的を実装した本質です。コントローラは本質とそれ以外の関連付けです。この「はじめてのフレームワークとしてのFuelPHP」では、最初、無目的に機能を遊んでいるうちはずっと、コントローラの中でやります。で、だいたいこのフレームワークがどういうものかわかったら、実用を意識した実験をして、その次にようやく「ではこういうアプリケーションを作りましょう」と決めて、やっとモデルになるクラスを作り始める。しかもそれは、最初はメールを送るという、ストレージを持たないサービスときたもんだ。そう、モデルはDBの行じゃなくて、アプリケーションの機能の親玉。まずそういうMVCの意味を理解するのが最初にあって、ORMなんかはもっと後にこういうのもあるよって話になる。

うん、正しいですね。とにかく最初にDBのCRUDから入るタイプのフレームワークを題材にしちゃうと、なかなかこういう学習プロセスは提供しにくいでしょう。プレーンPHPCMSのカスタマイズよりは技術的に高度で、かといって、いきなり一発楽ちんが出来上がっちゃってるフレームワークじゃないもの、という意味で、このFuelPHPはいい題材だと思いました。題材がこうだから本の展開がこうなったのか、本の展開が先にあったところに題材がハマったのか...は、わかりませんが、まあたぶん両方なんだろうなと思います。

それと、いちいち単体テストが徹底しているのもいいですね。もしかして、MakeGoodをこんなに詳しく紹介した出版物って、初ではないでしょうか。Eclipse+PDTの人はぜひMakeGoodを。MakeGoodに清き一票を。

そうそう、あと、前述してますが、この本ところどころに、「FuelPHPはこういうのがまだ不十分」という説明が入ってきます。これ実はいい感じです。フレームワークは完璧なブラックボックスだと思って信じてると、裏切られることもあるんですよね。中を見れば、たまに自分の期待とは違う意図で書かれたコードもあるし、TODOしか書かれてないことだってあるし、もう未完成な設計や見落としケースはしょっちゅう修正されてて、だからこそ、進化するために何度もリリースするんですよね。そのへん包み隠さないことで、フレームワークのバージョンとの付き合い方を意識するメッセージにもなってる気がします。魔改造で置き換えるより本家の修正リリースのほうが有利だとかそのへん。

まあ、FuelPHP 1.2代は、機能はいろいろあるけどOOP的に微妙な設計に感じるところもあるし、いろいろ名前が短いのはいいけどPSR-0準拠じゃなくて一貫性がなかったり、PHPUnitはいいけどコアのテストが一部メソッド空っぽ(!?)だったり ...と、人によってはまだ満足できるものじゃないと言われるかもしれません。が、より正しい道順を追って学ぶための足場として、プレーンPHPでもなく、いきなり高度なところから始まるフレームワークでもなく、ちょうどいいところにあるものなんだなと、改めてCodeIgniter系の作りの価値を再認識しました。

繰り返しますよ。この本は「フレームワークを使った今どきのWebアプリ開発のスキル標準」を「たとえばFuelPHPを使ったら」で教えてくれるものですよ。なのでこの本の思想は、他のフレームワークでもきっと役に立ちますよ。Fuelであるということに気を取られすぎなければ、これからWebアプリ開発本気出すと思ってる人なら、誰が読んでも楽しめます。もしまだ自分のホームになるフレームワークがない人がいたら、この本読んだんなら、そこを足がかりにまずはFuelPHPをゴリゴリに学んでから視野を広げていくのが、スキルアップの最短コースじゃないかなと思います。

とりあえず、本で学べる機能は吸収してと...さて僕は2.0から本気出すか(違!?

ところで二番目のフレームワークとしてのYii... だれか

P.S.
僕が最初にFuelPHPで作ったプログラムです:

https://p.twimg.com/AxDJTaHCMAICDYJ.png
https://twitter.com/tanakahisateru/status/220897717000482816

※注: アニメーションはありません。

PHPのarrayをリストとして使うときはunsetしちゃダメという話

タイトルそのまんまです。

PHPのarrayは順序付き辞書なんだけど、リストに見えちゃうのでついついやってしまうのが $a[count($a)-1] こういうの。善良なプログラマほどこの罠にかかるから、こういうときはunsetじゃなくてarray_spliceを使おうね。

PHPのinterfaceなめんな

はいタイトルは釣りです。

OOPのインターフェースはただの実装漏れチェック機能じゃないし、ましてや継承は差分プログラミングツールじゃないぞ。というのはわりと一般的な話だけど、Ruby(respond_to?でホントにいいの)とJava(インターフェースが自然すぎてユーザが意識しないのよ)が、PHPに対してOOPどうこうで偉そうに言うのはどうかなと思ったもので。まあそれと同時に、PHPの人自身がその意義を発見してるのかなという疑問もあったりしたんですけどね。

Rubyというのは「オブジェクト指向ってのはつまりメソッドに応答できるアヒルはみんなアヒルとみなせるよね」というレベルのダックタイピングで割り切った言語だと、個人的に認識しています。継承とミックスインにはis_aが応答するけど本質はrespond_to?のほうで、インターフェースを宣言してなくてもメッセージ送れたらいいあの感じ。

そんなRubyでオブジェクトが特定の機能の「セット」を実装しているかを調べて、アヒルかどうかを分岐するコードはこんなふうになります。

めんどくさいですね。おっと、ここで継承かミックスインで解決してis_aを使えばいいというのはナシです。単一継承の言語における継承はそうそう安易にできるものではないですね。OOPで設計してる人なら、本質的に意味の違うものを同じ継承ツリーの枝に入れないといけないとき、辛い思いをしたことは何度となくあるはず。

ミックスインなら同じ継承ツリーじゃない、ってことでミックスインをマーカーに使おうとするとこんな感じ。

機能的にはだいぶいいけどちょっとだけ残念。でも「ミックスインは機能の混ぜ込み」だという本来のコンセプトに反した使い方なので、人にわかってもらえにくい気がします。

いっぽう、Javaではインターフェースとメソッド実装のコピペ自動生成を分けてやることで、オブジェクトに複数の顔をもたせられます。まあその代わり、メソッドに渡す型の制約が強すぎて、アヒルを扱うにはいろいろめんどくさい子です。でもたまに型がRubyお得意のダックタイピングに勝ることもあります。

いまこれRubyのダックタイピングの例と同じ意味のことをやってるんですが、そうは見えませんね。ここちゃんとやり始めると、MLとかそっちの「型」の本質の話になってしまって、PHPをdisる人よりもっと恐い人が来るのでやめときます。分岐をコンパイル時ではなく実行時に持ってくると、こうなります。

だいぶLLっぽくなりました。インターフェースがくっついているかどうかを分岐の根拠にしたりするテクニックはマーカーインターフェースと呼ばれ、マイナーですがあります。ああでもやっぱ、型のある言語の本質は前のやつが何も意識しなくてもできることなんですよねホント... いいなぁ。

さてさて、PHPだとどうなるか。Javaのコードは手抜きしちゃいましたが、ここが本題なのでというわけで:

PHPさん意外にも超スッキリ!

PHPみたいに変数に型がない(値に型があるのとは違う意味ね)言語におけるインターフェースというのは、Javaの教科書に書いてある、「実装の制約」と「入出力型のコンパイラチェック」用ではなくて、むしろJavaでは応用的なほうだと思われてる、マーカーの意味合いが強いと思うのです。PHP で instanceof があのグローバル関数のカオスに紛れていないファーストクラスの演算子だというのは、そういう意味なんじゃないでしょうか。たしかにアノテーションの記述性が高ければそっちでも良かったぐらいのものなんだけど、それに十分な表現力を持たせようとすると、必然的にJavaのinterfaceみたいになるので、偶然にもPHPの選択は正解だったとようやく最近思っています。

たしかに、Javaみたいにコンパイル時に型の分岐が済んでいるのはありがたいのですが、オブジェクト指向以外に型理論まで意識しないといけないのは、楽しい楽しいプログラミングの本質を遠ざけてしまうと思います。これはずっと最初からRubyが教えてくれたコンセプトだと思うし、だからこそLAMPブームが起こったわけで、なので、安直に型に支配されるほうが良いとはあまり言いたくないです。(OCamlScalaの人がなんか言いそうですが、型推論は記述量を減らせても型の本質的高度さから逃れることはできないと思うのでちょっと...)

PHPのコードでもっとも大事なのは、

  • 抽象クラス => インターフェース + 実装差分
  • インターフェース + 実装差分 => 抽象クラス

というセオリーが成り立ってるということです。だだ綺麗なのが目的じゃなくて、意図が明確でトリッキーじゃないというのが大事。

僕は抽象クラスの継承がインターフェースと実装差分に分けて考えられないのは、ちょっと不健全な気がするんです。そういうのって、結局継承システムがその本質である「概念の抽象レベルの階層化」に使われず、ただの実装差分としてしか意識されなくなって、ロジックさえ全部書いてあればいいんじゃないかという錯覚に陥る危険性もあるんじゃ...という危惧があります。
やはり、継承とミックスインだけあってインターフェースがないとか、継承とインターフェースだけあってミックスインがないというのは、ちぐはぐな感じがするんですね。普通に生産的で使いやすいオブジェクト指向言語というのは、差分プログラミングするかどうかと、APIインターフェースの設計をどうするかという問題とは、直交しているべきだと思います。

たしかにPHPも、5.3まではJavaのようにちぐはぐでした(おっと5.3未満のことは言うな)が、5.4でトレイトが入ってくるので、やっとこれで役者が揃ったように思います。(クロージャという名のRunnableの無名インナークラスはすでに5.3で入ってますしね)


しかしarrayとリファレンスと文法パーザの作りはそれ以前の問題だ、という声が聞こえなくもないですが、たとえば何の取り柄もない幼馴染みがごくまれに上手にお菓子とか作ったらかわいいじゃないですか。