php empty 関数ではまった

このエントリーは IT エンジニア向けです。

何の因果か、最近 php を書いている。最後に php 書いたのいつだろう?確か iPhone アプリのサーバーサイドを実装した時かな。もう金輪際 php は使いたくないと思った日々が懐かしい。まあ、最近は type hint もついたし、php も昔ほど嫌いじゃないけどね。

そんな中、久しぶりに php 書いたら若干ハマったことが合ったので書いてみる。

俺は Bitcoin に代表される暗号通貨関連の仕事をしている分けだが、残念な事に php では関連するライブラリがまだ少ない。どっかのオープンソースから拝借しようかとも思ったが、php 製の有名なオープンソースも見つからなかった。(探せば有るんだが、わざわざソースをハックする信頼性や価値が有るとは思えなかった。)

ってな分けで、俺の感覚ではどっかのライブラリ使いたくなるような下回りのメソッドも今回は自力で実装するハメに。とはいえ、俺自身、暗号通貨についての知識はまだ浅いし中、下回りの実装は勉強にもなるので悪いことばかりではない。

半分イヤイヤ、半分ウキウキでライブラリの実装を行った。

ところが、このライブラリを使った環境で負荷検証でポチポチエラーが出てくる。エラーの原因は負荷ではないっぽい。プログラムのバグだ。

「エッヂケースかな?」と思い、色々な境界値を入れてテストしてみたが、正常に動く。分からん。

至る所に var_dump を入れ print デバッグを行っていると、巨大整数の取り扱いでエラーが起こっているような気がしてきた。

ご存知の方も多いかもしれないが、php ではネイティブで巨大な整数が取り扱えない。俺の環境では、整数は 64 bit の固定長だった。64 bit ではとても足りなかったので自前で巨大整数を扱う関数を作ったのだ。そこでエラーが発生しているらしい。

ただ、正直なところ最初は信じられなかった。

ここでエラーが起きると後で面倒な事は分かりきっていたので、テストも少し入念に行った。一方、これらの機能は副作用が無いのでテストはどれも簡単だ。それなのに、本当にここでエラーが起きるのか?

半信半疑で再度色々とやってみると、驚きの結果が。

なんと、48 という数字を用いた時だけ四則演算(足し算、引き算、掛け算、割り算)の結果がおかしくなっていたのだ。何でよりによって 48 ?全部エラーなら分かる。0, 1, 255, 256 というコンピューター的に特別な値だけでエラーが起こるのも、分かる。でも何で 48 ?

完全に混乱しながらデバッグを続けて、やっとわかった。

php 組み込みの empty 関数だ。

empty はデータが空かどうかを判断する。例えば、空の array や空の string を渡すと TRUE を返し、それ以外の場合は FALSE を返す。

と、思っていた。

だが実際には、少し例外が合ったようだ。

‘0’ という文字列 (数字の 0 を表す文字列) を渡した時も empty は TRUE を返す。

俺は大きい整数を扱うために整数を byte 列に変換し、string として保存していた。そして、その string が空の場合は数字の 0 として扱うよう、empty を使って文字列をチェックしていた。ところが 48 という数字を byte 列にすると php が文字列の ‘0’ と解釈し、empty が俺の意図に反する挙動を示したのだ。(‘0’ の ascii コードは 48)

つまり、48 という数字が所々で 0 に変換されていたため、計算結果がおかしくなっていた。php プログラマの間では常識なんだろうけど、知らなかった。

php の型は超弱い事は知っていた。だからこそハマるとしたらこういう所だと思って注意していたのに、それでも落とし穴を踏みぬいてしまった。なんか悔しい。

書評 「The Goal」 おまけ 「トラブルの渋滞」

「The Goal」はアメリカで 1984 年に出版されたビジネス書だ。

ネットで調べる限りは凄い本のようだ。

アメリカで初版が発行されるとたちまちベストセラーになったとの事。しかし、その後 15 年以上日本では出版されなかった。ダイヤモンド社 書籍オンラインによると、「日本で出版されると世界経済が破滅してしまう」と言って著者が拒否したらしい。そして 2001 年にようやく日本語版が出版されると、日本でもたちまちベストセラーになったそうだ。

普段はネットのニュースや新しい物ばかりに目がいってしまうのだが、たまには時代の検証を経た古典の名著も読んでみようと思い購入した。(古典というには新しすぎるかもしれないが。) kindle で電子書籍版が出ていたのもでかい。

本は物語ベースとなっている。ライバル社におされて危機に貧している工場のマネージャーが部下とともに経営を立て直していくストーリーだ。物語の中では具体的に何の工場かの表現は無かったが、何となく自動車工場に思えた。おそらく、ライバルは日本の会社をイメージしているだろう。初版が 1984 年という事なので多分間違い無いと思う。時はまさにバブル前夜。当時の事はよくわからないが日米の貿易摩擦が一番激しかった頃では無いだろうか?

さて、今回は崇高な目的で勉強しようと思い読んでみたのだが、正直なところ期待はずれだった。

本 1 冊をかけて言っている内容は結局以下の 4 点。

  • 企業の目標は利益を上げる事。だから、施策の効果測定は「最終的な利益に繋がるかどうか」で行うべき
  • 問題を解決する時はボトルネックを見つけて、その部分を解消しなくては行けない。ボトルネックをを解消するために、それ以外の所が多少効率悪くなっても良い。
  • ボトルネックの改善を行っていくと、問題のボトルネックが次の場所に移動するかもしれないので注意
  • 全てが計画通りに行くとは限らないので、「予定外」を吸収するための遊びを随所に入れておけ。最適化しすぎてこの遊びを殺さないように注意

この 4 点は 1984 年当時は斬新なアイディアだったのだろうか?俺には当たり前過ぎて、「どこで伏線が回収されるんだろう?」と逆に疑ってしまったじゃないか。こんな事、IT エンジニアだったら誰でもやってるよ。多分、他の分野でも当たり前じゃないのかな?

たったこれだけの事を言うために数百ページをかけている。「時間という検証を経て名著と判定されたこの本なら、どこかで何か凄い事が書いてあるかもしれない」と思い頑張って最後まで読んだが、肩透かしをくらった気分だ。

ところで、この記事を書いていて「渋滞学」について少し勉強した事を思い出した。

「ボトルネックを解消しろ、遊びを残しておけ」というのは、まさに渋滞を発生させないための方法だ。残念な事にこの本はそこで終わってい待ったが、渋滞学ではその逆の研究もしている。つまり、「渋滞を意図的に発生させるにはどうしたら良いか?」である。

例えば、山に植林する場合。等間隔に木を植えるより、木が密集している部分とまばらな部分を作った方が山火事の延焼速度が遅くなる。木がまばらな所で延焼の渋滞を起こすのだ。

このアイディアをビジネスに応用して、「トラブルによる被害を抑制するため、トラブルを渋滞させる事はできるか?」を考えてみる。

おお、俺、良くやってるじゃん。例えばプログラムを作るとき、要所でサニタイズ(途中経過のチェック)を入れ、問題がある時、疑わしい時はエラーにする。最悪、クラッシュさせても良い。非エンジニアの皆さんは、例えばネットで何かを購入する事を想定してほしい。システムに何か問題があった時、「画面が乱れたけど最後まで進み、金を払ったが結局商品が届かない」より、「エラー画面が出て購入が最後まで勧めない」方がよっぽど良いだろう。

あれは「トラブルの連鎖を防ぐため、意図的にトラブルの渋滞を作っている」とも考えられるだろうか?いや、ちょっと違う気もするな。トラブルの被害を最小限に抑えているのは確かだが、「渋滞」とは少し違うような。。。

じゃあ、時々有名人や問題起こした企業がやってる、炎上の火消しは?

ネット上のヤバイ書き込みを無かった事にしたり、SNS の拡散を抑制したりするやつ。こっちの方が「渋滞」をいう言葉にはマッチする気がする。伝達速度を抑制している分けだからね。でも、良い印象はしないし、成功率があまり高くなさそうな印象。火消しに成功した事例には気づかず、失敗した事例だけ目にするせいでバイアスがかかっているのかもしれないが。いずれにせよ、自分は関わりたくない。

じゃあ、全く新しいアイディアはどうだろう?う〜ん、ゼロから思いつくのは難しい。。。

我ながら発想のスタートとしては独創的で悪くない気がするが、良いアイディアが思い浮かばない。でもまあ、新しいインスピレーションの卵を得たという事で良しとするか。

ドラゴンクエスト ホイミ味 ~旅立ちの物語~

2016 年 5 月 10 日 朝。

「2 日間休めば 10 連休」というまれに見るゴールデンウィークも明け、暦は「68 日間祝日無し」というハードモードに突入した。
それを反映してか、世間には陰鬱な雰囲気がどことなく蔓延している。

もっとも今年の俺にはゴールデンウィークなぞ無かった。リリースを目前に控えて土、日も出勤をした俺は目覚まし時計を気だるく止め、いつものように窓を開けて空気の入れ替えをしようとした。折しもその日は朝から雨が振り、天気までもがどんよりとしている。

「今日は雨か。雨の中出勤するのだるいな。」

諦めて窓を閉めた俺は、その気怠さを流し込もうと冷蔵庫を開ける。ひんやりとした空気が顔にあたり心地良い。だが、そこに目的の牛乳は無かった。

「そうだ、昨日最後のパックを飲み終わってから買っていなかった。」

時計を見ると 9 時 45 分前を指している。時差出勤をしている俺は 10 時半に家をでれば会社に間に合う。まだ時間はあるようだ。

「そこのコンビニまで買ってくるか。」玄関の扉を開けアパートの階段を降りると、やはり雨が降っていた。

「そういえば、さっき窓開けた時に雨降ってたもんな。わざわざ牛乳買いに行くもも億劫だな。」

窓を開けて雨を確認しながら傘を持たずに出てくるとは、まだ頭が起きてはいないらしい。だが、もうアパートの階段を降りてしまった。。幸い、コンビニはアパートのすぐ近くだ。傘が無いが走れば大して濡れないだろう。

俺はアパートの玄関を出ると小走りに急いだ。

コンビニでは、通常飲み物売り場は一番目立つ位置にある。ここも例外ではなく、目的の牛乳が並んだ棚はすぐに見つかった。やはり、いつものスーパーよりは高いようだが仕方ない。まさか今からスーパーに行くわけにはいかないだろう。

俺は並んだ 3 種類の牛乳から一番安い物を手に取ると、レジに向かった。

店員はレジにおらず別の仕事をしている最中だったが、俺を見ると作業を中断し、急いでこちらに来た。その様子を何気なく見ると、ふと目に入ったものがある。

ドラゴンクエスト ホイミ味だと!

そうだ、そういえばネットでそんな記事があったな。確か 5 月 10 日発売だった。楊枝がロトの剣バージョンになっていて、この楊枝が数量限定、売り切れゴメンだった。あと、何か集めるとスライムの何かが当たるんだよ!

値段を見ると 200 円。さっき「スーパーより高い」と心の中で文句をつけた牛乳より高いのが少し気になるが、ここは迷わず買ってしまった。

すると、「テレテレッテレーン」とレベルが上がる音が。あ、そういえばそんな事も書いてあったな。購入するとレベルの上がる音がするんだった。

驚きの表情が顔に出てしまったのだろうか。そんな俺を見て、店員さんが恥ずかしそうにした。うん。今朝発売だからね。彼女もまだ慣れていないというか、反応されると少し恥ずかしいのかもしれない。

ちなみに、商品の写真はこんな感じ。

右に刺さっている爪楊枝を外すとこう。

爪楊枝を袋から出さないのかって?

「これを使うなんてとんでもない」

永久保存版ですよ。これは。

ちなみに、裏はこんな感じ

宝箱の絵の中に番号が書いてある。これがプレゼントの抽選番号になるんだろう。一応黒塗りしておいた(画像が荒くてどうせ読めないと思うけど。)

食してみると、まあ普通の唐揚げ。「ガーリックマヨネーズ味」とあるが、言われなきゃ分からない。というか、俺的には言われても分からなかった。(味音痴?)

パンチが無いので「この味が大好き」という人は珍しいとおもうが、同時に嫌いな人も少ないのでは無いだろうか?良くも悪くも万人受けすると思う。味音痴の俺が言っても説得力無いかもしれないが。

いやー、嫌な天気だったけど、朝からレベルが上がってよかった、よかった。

ちなみに、どうでも良い情報だが。最初の物語風のところはほぼノンフィクションである。俺の家に冷蔵庫は無いが、あとは本当。