以下のようなコードを考えてみる。
$num = floor(0.5);
if ($num === 0)
{
echo "\$numはゼロ\n";
echo "\$num = " . $num;
}
else
{
echo "\$numはゼロ以外\n";
echo "\$num = " . $num;
}
これは次のように出力される。
$num
には0
が入っているにも関わらずif ($num === 0)
を通らず、else
側の内容が出力されている。
これはif文で使用している厳密等価演算子===
が影響している。
$num
に代入しているfloor(0.5)
の戻り値は0
だが、floor()関数はfloat型を返すため、結果が整数であってもその値の型はfloat型になる。
対してif ($num === 0)
の部分に記述されたリテラル値の0
はint型となる。
厳密等価演算子===
は値と型が厳密に等しい場合のみtrueを返すため、float型の0とint型の0は異なるものと判定する。
それにより上記のような問題が発生するわけだ。
これはもちろん0
以外を比較した場合も同じであり、例えばif (floor(1.5) === 1)
というif文も同様に素通りしてしまう。
またfloor()
に似たceil()
やround()
等もfloat型を返すため注意が必要だ。
大きく分けて2つの方法が考えられる。
ひとつは厳密等価演算子===
を使用するならば比較対象を双方共同じ型に統一して比較する方法。
あるいは厳密等価演算子===
ではなく通常の等価演算子==
を使用して型を無視する方法もある。
$num = floor(0.5);
// 0ではなく0.0と記述することでfloat型に統一する
if ($num === 0.0)
{
echo "\$numはゼロ\n";
echo "\$num = " . $num;
}
else
{
echo "\$numはゼロ以外\n";
echo "\$num = " . $num;
}
if文の条件部をif ($num === 0.0)
と記述することにより、比較対象をfloat型に統一する。
floor()
やceil()
は必ず整数値を返すため、以下のようにint型に統一する方法もある。
$num = floor(0.5);
// $numをキャストすることでint型に統一する
if ((int)$num === 0)
{
echo "\$numはゼロ\n";
echo "\$num = " . $num;
}
else
{
echo "\$numはゼロ以外\n";
echo "\$num = " . $num;
}
$num = floor(0.5);
// === ではなく == を使用する
if ($num == 0)
{
echo "\$numはゼロ\n";
echo "\$num = " . $num;
}
else
{
echo "\$numはゼロ以外\n";
echo "\$num = " . $num;
}
厳密等価演算子===
ではなく通常の等価演算子==
を使用する。
この場合厳密な型の判定が行われないため、値さえ同じであれば等しいと判定される。
通常の等価演算子==
を使用する方法はお手軽だが、暗黙的な型変換により思わぬ結果をもたらす場合がある。
今回は比較対象が双方ともに必ず整数だとわかっているが、そうでない場合は充分注意が必要だ。
厳密等価演算子===
は結果にイレギュラーがない演算子だが、今回のようなパターンではバグの原因になることもある。
かといって通常の等価演算子==
では更にイレギュラーが発生しやすいのでやはり厳密等価演算子===
を使うよう心掛けた方が良いだろう。