« 面白法人カヤックで働いています | メイン | #isucon で優勝させてもらってきました »

2011年3月27日

悪いけど正しいかもしれないPHPerになるための10個のTips

流行っているみたいなので書いてみた。かなり独断と偏見に満ちたエントリになっています。決定的な間違いがあったらブクマコメ等で指摘願います。

さて、そもそもPHPとはなんのための言語か。HTMLの延長線上で使える学習コストの低いテンプレート言語であり、多少汚くても良いから、Webアプリケーションを手っ取り早く作るための言語です。

色々なユーザーの声をやたらめったら取り込んでしまったせいで、日本の家電みたいに無駄かつ一貫性のない機能が満載で醜悪なことになっていますが、その辺は気にしないことにしましょう。

ただ、変に多方面の声を取り込んでしまったせいで、妙にお行儀よくなりたがっている部分も多く、使いづらくなっている部分も多々あったりして困りものですが。

まあ、つまりPHPにおいて「良い」ってのはありえないんですよ。とか言ってみたりして。

閑話休題。

エラーレベルは最大にしろ

色々コードが書きづらくなる部分もありますが、逆にお行儀がよくなり分かりやすくなる部分も出てきます。また、前方互換も考えると、最大限有効にしておくのが賢明でしょう。

PHP.iniに以下のように書くのが理想です。

error_reporting = E_ALL | E_STRICT

PHP.iniを触れない場合、スクリプト内に以下のように書くこともできます。

error_reporting( E_ALL | E_STRICT )

ただ、この場合、コンパイルレベルでのエラーを一部出力してくれなくなるので残念です。

.htaccessに書くこともできますが、その場合は定数を使えず、即値を使わないといけないので、一長一短ですね。

あと、PHP4と互換性のあるモジュール(MDB2とか)なんかを使うときにエラーがたくさん出て困ることになりますね。このあたりどうすれば良いんでしょうね。

エラーレベルを動的に変更できないところがPHPの辛いところ。


文字コードはUTF-8一択

理由は色々ありますが、大きな理由としてはマルチバイト文字を扱うときにUTF-8じゃないとpreg系の関数が正しく動かないことです。

mb_regex_encodingを適正に設定して、mb_ereg系を使うという手もありますが、mb_ereg系では、各種正規表現修飾子が使えないのが痛い。特にx修飾子が使えないのが致命的。


正規表現はpreg系を使い、x修飾子を積極的に使いましょう

x修飾子超便利。


変数名には「意味」を持たせる。型は持たせない

型は意味ではない。変数の型付けに拘るのは静的型付け言語の考え方であり、動的型付け言語は無意味。

例えば、my_ageだったらintegerに決まっている。それをiMyAgeなんて変数にするのはナンセンス。

それに、追加開発時にmy_ageはintegerではなくて、ageクラスのインスタンスに仕様変更されるかもしれない。そういう自由さを動的型付け言語は持っている。そうなったときに、変数名がiMyAgeのままだったら目も当てられない。

ただ、同じ変数の型がプログラムの中でコロコロ変わるなんてのは分かりづらいのでやってはいけません。これは、次の「真理値を返すのは真理値を返すメソッドのみにする」でも触れます。

それと、キャメルケースは案外読みづらい。変数名はアンスコ区切りが良いんじゃないかと思う。


真理値を返すのは真理値を返すメソッドのみにする

PHPは動的型付けなので、メソッドの途中で失敗したらfalseを返すみたいなこともやってしまいがち。

しかし、正しくはメソッドの戻り値の型は固定にして、メソッドの途中で失敗したら例外を投げるべき。falseを返すような実装にしてはいけない。呼び出し元でイチイチ戻り値をチェックしないといけなくなり、コードの見通しが悪くなります。

メソッドが真理値を返すのは、そもそも、is*とかcan*とかtrueかfalseを判定するメソッドに限るべきです。


var_dumpとかアドホックな出力に頼るな

たしかにvar_dumpは便利だ。ただ、デバッグ値を画面に出力するだなんてのはあまりにもダサい。そんなことだから、PHPerがバカにされるのだ。

var_dumpの内容はデバッグログに吐くべきだ。それには多少工夫が必要になる。以下のような感じだ。

function d(){
    ob_start();
    ob_implicit_flush(0);
    $args = func_get_args();
    call_user_func_array('var_dump', $args);
    $str = ob_get_clean();
    return $str;
}

出力ストリームをトラップして、戻り値として返すようになっている。var_dumpは可変長引数をとるのでそれも受け付けるようにしてある。

上記関数を以下のようにロガーに渡して、ログファイルをtail -f で見ろ。そうすれば変数の変化なんかも追うことができる。

$logger->debug(d($obj));


三項演算子はネストしない

三項演算子は便利だがPHPだと連結順がおかしいのでネストしない。括弧で囲んで頑張ってネストさせる手もあるが、そこまで頑張らなくてもよいでしょう。

switch文が便利なこともありますが、例によって「緩やかな比較」なので注意。

ちなみに、PHP5.3以降は?:演算子も使えるのでちょっと便利。


$_GET$_POSTを使え

$_REQUESTを使うのはもちろん論外だが、$_GET$_POSTをイチイチちょっとしたクラスでラップする必要性も感じない。ユーザーの入力値を使いやすい形で提供してくれているのだから使うべきだ。

もし、オブジェクト化したら、キーをなめるような処理が欲しくなった時にkeysみたいなメソッドを生やさなくてはいけなくなるような不自由さが発生するし、そもそもアプリケーションがWebからの入力を前提とした作りになってしまう。

上手くクラスを利用するとしたら、バリデーターオブジェクトをつくってそれに$_POSTを喰わせるとか、フォームオブジェクトを準備しておいてリクエストに対して自動で$_POSTの中身をバリデーションするとか、そんな時でしょう。その場合も、$_GET, $_POST自体をラップしておく必要はありません。

そして、ちょっとしたアプリケーションであれば、生の$_GET, $_POSTで困ることは少ないのです。

ただ、$_GET, $_POST, $_COOKIEあたりを事前にmb_check_encodingを通して、不正な入力値が与えられていないかはフレームワーク側で担保しておいたほうが良いでしょう。


設定ファイルはアプリケーション設定ファイルと環境設定ファイルの2種類持て

最近は、アプリケーションの設定をする設定ファイルと、環境情報を記載した設定ファイルの2種類を準備したほうが良いんじゃないかと思い始めている。

そして、環境情報ファイルは本番と開発用で分けておくが、アプリケーション設定ファイルは本番と開発用で共通して使えるものにしておく。

アプリケーション設定ファイルが肥大化してきたら、一部の設定値や定数群をモデルクラスにアサインした方がよくなってくるでしょう。もちろんモデルだからといって、ストレージはDBとは限りません。


short_open_tagを有効にし、テンプレート内では<? ?>を使え

最後に超独断の爆弾。

個人的にはコントローラやモデルは<?php で書き始め ?>で閉じないように書いていますが、テンプレートでは<? ?>を使うのが好きです。

short_open_tagをoffにして、テンプレート言語としてのメリットを捨ててまで、PHPみたいな(censored)な言語を使う理由を全く感じません。

よく言われるのが、XML宣言云々ですが、そこだけechoで書けばよいだけの話です。なんでそこでechoを使わないためだけに、他のところでechoを使わないといけないのか意味がわかりません。

あと「他の環境に持って行っても動くように」なんて話もありますが、それも.htaccessに書けば良いだけなんでないの、とか思ったり。

理想を言えば、最近のトレンドからして、<?= ?>で囲まれた部分はオートエスケープされるようにPHP側で良きに計らってくれるようになってくれれば良いな、と思う。もちろん後方互換を考えてPHP側でなんらかの環境設定フラグを準備してもらう必要はあるでしょう。またPHPにフラグが増えることになりますが。

投稿者 Songmu : 2011年3月27日 23:22