おまいらもっとextract()使い倒せ!!

http://www.machu.jp/diary/20080906.html#p01

いやいや.extract()は便利な関数です.使うのをやめるのはもったいない.
もう少しだけ覚えることができちゃいますが,少しだけなのでそれを覚えてextract()をもっと使い倒しましょう.

決め事

1個だけルールを追加してしまいましょう.それができればextract使い放題です.下記はそのルールの一例です.

大文字アルファベット1文字とアンダーラインで始まる変数名(例えば「P_」,「G_」,「S_」)はextract専用

例えば「$S_foo」,「$S_bar」といった変数名はextract()で作成される変数の名前として予約し,自分で設定はしないようにします.

実際のコード

上記を併用し,extract()には第2引数に必ずEXTR_PREFIX_ALL,第3引数に大文字アルファベットを追加します.

extract($_GET, EXTR_PREFIX_ALL, 'G');
extract($_POST, EXTR_PREFIX_ALL, 'P');
extract($_SERVER, EXTR_PREFIX_ALL, 'S');

あとは「自分がまるまる作成するような変数」は上記ルールにかぶらないように記述しましょう.下記はとても手抜きですけど(苦笑 一例です.

$ php -r '$foo = array("foo", "bar", "baz"); $foo = array_flip($foo); var_dump($foo); extract($foo, EXTR_PREFIX_ALL, "F"); var_dump($F_foo, $F_bar, $F_baz);'
array(3) {
  ["foo"]=>
  int(0)
  ["bar"]=>
  int(1)
  ["baz"]=>
  int(2)
}
int(0)
int(1)
int(2)

EXTR_SKIPの危うさ

EXTR_SKIPって便利!!って思う人は条件や環境によって「配列から変数を設定しているはず」と思い込む可能性が高いと考えます.
そんな不安定な状況にならない人や状況を的確に判断できる人は,おそらくそもそもextractを使っても使わなくても困らない状況判断力があると思います.

根本にある問題は?

ようするに「この変数(の値)を誰が用意したのか判断できない」人が組んだコードの品質に問題があります.
なので,extractに関しては上記ルールでネームスペース的に追い出し,「〜のルールに従う変数はextract()以外は誰も設定しない」ということにすればよいのです.

実はこのネタの背景は別にあってもっと根が深いのでは?

この辺で問題になる人は,どういう変数が利用できるか(あらかじめ設定しなければいけないか)管理することができないのではないかと考えます.
自分でそういうのが気になる場合は,過去にこういうコードを書いていないか思い出してみてください.

$name = isset($_GET['name'])? $_GET['name']: '';

$rows = $db->getAll('SELECT * FROM the_table WHERE ...');
foreach ($rows as $row) {
    $name = $row['name'];  //  変数名の衝突

    //  いろいろなコード
}

これは「連想名がnameだから変数名も$name」とか安直につけちゃったときの例.まれにこういう問題で不都合を起こすケースが見受けられます.
こういったことは自分がどういう変数を使っているのか的確に管理できていれば起こることがありません.
「今でもこういうコード書いてしまいそう!!」とか思った人.あなたはextract()以前の話があるようですよ.

余談

とかね。 次の PHP6 とかで古い互換性をバッサリ捨てて、シンプルで安全なテンプレートエンジンになってくれるといいなぁ。 とりあえず、以下のところだけを整備してくれれば他はいいから!

* echo や printf などの出力値はデフォルトで HTML エスケープされる
* DBへのSQL文は prepared statement を標準にする

1個目は出力制御系の関数群(ob_startとか)を使えばいいですね(そもそもそういうポリシーは,echoとかでHTMLを生成している人は困ると思うんだけど.本質は多分別).
後者はPHPでは多分いまどきPDOが標準なので,ほとんどの人はそれを使えばいいだけですね(PDOで使えないDB使っている人.残念ですね).
PDOを使えない環境の人,早くその環境をどうにかするか,PEAR::MDB2などが利用できる環境に移行したほうがいいですよ.

まとめ(追記)

っで自分はどうなのか? というと,私はほとんどextract()使っていません,そういう文化にいるので(苦笑
基本的に私は「今から何を使う」を明確にしたコードを書きたい人です.いわゆるホワイトリストを作りたい人.
なので例えばで言うと,「自分が使いたい連想キー一覧」を用いて展開します.

$lists = array('foo', 'bar', 'baz');
foreach ($lists as $name) {
  $name = 'F_'.$name;
  $$name = $foo[$name];
}

連想キーと値を一緒にしちゃったのはシクった(苦笑
普段「$name = 'F_'.$name」みたいなことはしませんが,前述の例とあわせるために追加しました.
ってことで私もちゃんと管理できない人みたいです.
お後がよろしいようで(爽

はてブ

extractを使うときのルール。でもやっぱり利用シーンが見えない…。$_GET['name']じゃなくて$G_nameと書けた方がいいことってあるのかなぁ?

10も20もフォーム要素渡すと地道にコードの記述時間とモチベーションの削られ方でてきますよね.
例えば実際問題シングルクオート,ダブルクオート打つのが面倒な人は要るかもね.
そういう人はシングルクオートは英語キーボードだとほとんど苦にならないので英語キーボードお勧め(脱線