PHPのnumber_formatを用いた計算にて
皆様、こんにちは。
先日、初歩的なのに気付けなかったミスがあり、自戒の念を込めて記事にさせて頂きます。
「こんなの当たり前!」って人もいるかと思いますが、記憶の定着にはアウトプットが良いということもあるので、しばしお付き合いくださいませ。
前提
- PHPバージョン
- PHP7.1
何が起こった?
表題、PHPのnumber_format()
を用いた計算でうっかりがありました。
現プロジェクトで料金をフロントで表示する時に,
区切りを付ける必要がありました。
int型の数値をそのまま表示ではマズイ訳です。
$a = 2000;
$b = 100;
echo number_format($a - $b); //1,900(string)
このような感じですね。
さて上記の既存式に追加修正で割引額を追加してくれ
となりました。
本来なら…
# 省略
$discount = 200;
echo number_format($a - $b - $discount); //1,700(string)
とすべきですね。
ところが半年前(!?)の私は…
# 省略
echo number_format($a - $b) - $discount; //?(?)
としていたようです。
どうなってしまったのか?
すでに上記結果で書いているのですが、number_format()の戻り値はstring
です。
ということは
# これは…
number_format(1900) - 200;
#こうなります
'1,900' - 200;
上記のような感じですね…よろしくないのが一目瞭然です…
結果
「でもPHPには 暗黙的型変換 があるんじゃ?」となりそうです。
これがうまく機能してしまえば(そもそも良くないのですが…)、1900 - 200
となるはず…
ところがどっこい!結果は…-199(int)
となります!
どうやらstring
からint
への変換時に,
を変換できずに1
となってしまうようです。
暗黙的型変換時での,
の扱いについては出典が見つけられず…公式ドキュメントのここだよというのを知っている方がいたら教えて頂きたいです…
ちなみにintval()でも同様の挙動なので、,
が含まれている文字列数値はそこまでの数値になってしまうようですね。
所感
元々を考えれば)
の位置を間違えなければ良かったように思えますがそこは人間、間違いもやっぱりあるはずです。
テストコードがあれば防げるかと思いきや、number_format()
の引数が1000未満のテストケースだと引っ掛からないという…
ただ、カンマを付けた表示にしたい
という仕様であるなら、カンマを付けた
結果がどうなるかに考慮できればテストケースに落とし込めたようにも思えます。
やっぱりテストケース考慮は大事!という安直ではありますが、確実に必要な考えを学べただけでも良かったかなと思います。
おまけ
こういうイージーミスをコンパイル時に弾いてくれる静的言語
はやっぱり魅力ですね…(PHPも良い言語ですけどね!)