PHP の配列を使った手品とその種明かし

PHP Advent Calendar 2013 に参加しています。昨日の @yando さんから引き継いで2日目。

以前 PHP を使った手品を人前でやったら、
会場から「えっ」「えっ?」「ええっ!?」
という反応があって楽しかったので書いてみます。

演じ方

まずはこちらをご覧ください。

これを実行したらどうなるでしょうか。

できれば、答え合わせをする前に
上記コードの右下にある view raw から
keys.php をダウンロードして実行してみてください。

普通に考えたらこうなると思います。

Array
(
    [key] => value_7
)

では実行してみますね。

% php keys.php
Array
(
    [key] => value_0
    [key] => value_1
    [key] => value_2
    [key] => value_3
    [key] => value_4
    [key] => value_5
    [key] => value_6
    [key] => value_7
)

こうなりました。

ここで「えっ!」とか「何これ気持ち悪い!」とか反応があったら成功です。

タネ明かし

上記コードの print_r のところを var_dump にすると
何かが見えてきます。

array(8) {
  'key\0' =>
  string(7) "value_0"
  'key' =>
  string(7) "value_1"
  'key' =>
  string(7) "value_2"
  'key' =>
  string(7) "value_3"
  'key' =>
  string(7) "value_4"
  'key' =>
  string(7) "value_5"
  'key' =>
  string(7) "value_6"
  'key' =>
  string(7) "value_7"
}

一つ目のキーがちょっと違って見えてますね。
ソースコードを Vim で開くともっとわかりやすい。

制御文字ですね。
PHP は配列のキーに制御文字が使える。

今回のようにブラウザで表示したり
ターミナルでソースコードを cat したりしても
制御文字は目に見えないので、
見た目では不可能に思えることができるというネタでした。

変なコードの書き方

いくつかのエディタでは、
制御文字をキーボードから入力することができます。

Vim だったら control + V を押してから制御文字を打つと
そのまま入力できますね。
Emacs だったらcontrol + Q ですか。

けど、どのコードがどのキーに割り当てられてるかいちいち覚えてないし、
そもそも 0x00 (Null) なんてキーボードから入力できるのかどうかもわからない。

ということで、上記のコードはこんなのを書いて生成しました。

いろんな文字を試してみる

せっかくなので ASCII 0x00 から 0x1F までの制御文字を
全部キーに入れてから出力してみました。

これを

実行。

% php keys_sample.php
Array
(
    [] => 00
    [] => 01
    [] => 02
    [] => 03
    [] => 04
    [] => 05
    [] => 06
    [] => 07
    ] => 08
    [   ] => 09
    [
] => 0A
    [
     ] => 0B
    [
     ] => 0C
] => 0D
    [] => 0E
    [] => 0F
    [] => 10
    [] => 11
    [] => 12
    [] => 13
    [] => 14
    [] => 15
    [] => 16
    [] => 17
    [] => 18
    [] => 19
    [] => 1A
    [%

00 から 07 まではさっきと同じく単に見えないだけだけど、
その次からわけのわからないものが見えますね。

    ] => 08

08BS (バックスペース) なので
1文字戻って最初の [ が消えてます。

    [   ] => 09

HT (タブ)。正しくは「水平タブ」ですか。
確かにタブが出てます。

    [
] => 0A

0ALF (改行)。
\n にあたるやつ。

    [
     ] => 0B

0B は、使ったことないけど VT (垂直タブ)。
垂直にタブしてます。

    [
     ] => 0C

FF (書式送り) なんだけど、
なんでこうなるのかよくわかりません。

] => 0D

これが CRLFCR にあたるやつ。 「復帰」ですね。
LF との違いが味わい深い。

一番の謎がここ。

    [] => 19
    [] => 1A
    [%

1F まで回したはずなのにここで止まってる。

1BESC (エスケープ) だから。
エスケープが出力された時点で
そこから先は回避されてます。

他の言語では

他のっていっても確認したのは Ruby だけですが。

キーに制御文字を入れることはできるんだけど、
何かちゃんとエスケープしてくれるせいで、できませんでした。

% ruby keys.rb
{"key\u0000"=>"value_0",
 "key\u0001"=>"value_1",
 "key\u0002"=>"value_2",
 "key\u0003"=>"value_3",
 "key\u0004"=>"value_4",
 "key\u0005"=>"value_5",
 "key\u0006"=>"value_6",
 "key\a"=>"value_7"}

というわけで、この手品は PHP でやりましょう。

この技の使いどころ

使わない方がいいと思います。

明日は @yohgaki さんですね。おねがいします。

  • このエントリーをはてなブックマークに追加