【PHP】’01’ == ‘1’ の結果は true

  • 2022年1月26日
  • PHP

 題の通りです。PHPではstring型の異なる値同士の緩やかな比較をした際、結果が true になる場合があるというやつです。
 PHP で同値を比較する演算子には=====の二種類があります。このうち===による比較を厳密な比較と言い、==による比較を緩やかな比較と呼びます。厳密な比較の場合、比較する値同士の型が一致していないならば問答無用で false が返ります。一方で緩やかな比較の場合、比較する値同士の型が一致していなくとも true が返る場合があります。例えば次の様になります。

// 厳密な比較
var_dump(1 === '1'); // bool(false)
// 緩やかな比較
var_dump(1 == '1'); // bool(true)

 この比較については次から引用した型の比較表が詳しいです。
 PHP: PHP 型の比較表 – Manual

== による緩やかな比較
TRUE FALSE 1 0 -1 “1” “0” “-1” NULL array() “php” “”
TRUE TRUE FALSE TRUE FALSE TRUE TRUE FALSE TRUE FALSE FALSE TRUE FALSE
FALSE FALSE TRUE FALSE TRUE FALSE FALSE TRUE FALSE TRUE TRUE FALSE TRUE
1 TRUE FALSE TRUE FALSE FALSE TRUE FALSE FALSE FALSE FALSE FALSE FALSE
0 FALSE TRUE FALSE TRUE FALSE FALSE TRUE FALSE TRUE FALSE TRUE TRUE
-1 TRUE FALSE FALSE FALSE TRUE FALSE FALSE TRUE FALSE FALSE FALSE FALSE
“1” TRUE FALSE TRUE FALSE FALSE TRUE FALSE FALSE FALSE FALSE FALSE FALSE
“0” FALSE TRUE FALSE TRUE FALSE FALSE TRUE FALSE FALSE FALSE FALSE FALSE
“-1” TRUE FALSE FALSE FALSE TRUE FALSE FALSE TRUE FALSE FALSE FALSE FALSE
NULL FALSE TRUE FALSE TRUE FALSE FALSE FALSE FALSE TRUE TRUE FALSE TRUE
array() FALSE TRUE FALSE FALSE FALSE FALSE FALSE FALSE TRUE TRUE FALSE FALSE
“php” TRUE FALSE FALSE TRUE FALSE FALSE FALSE FALSE FALSE FALSE TRUE FALSE
“” FALSE TRUE FALSE TRUE FALSE FALSE FALSE FALSE TRUE FALSE FALSE TRUE

 PHP の緩やかな比較の型の異なる際の挙動はこれで十分です。しかしながら緩やかな比較は上記表にある型変換に加えて、文字列同士の比較に際に特筆すべき挙動を起こします。具体例は次です
 Online PHP editor | output for s9ol0 ↓のデモです

<?php

var_dump('1' == '01');    // bool(true)
var_dump('1' == '001');   // bool(true)
var_dump('1' == '1e0');   // bool(true)
var_dump('1' == '  1  '); // PHP 8.0.0 以上ならばbool(true)。PHP8.0.0 未満ならば bool(false)
var_dump('1' == '1  ');   // PHP 8.0.0 以上ならばbool(true)。PHP8.0.0 未満ならば bool(false)
var_dump('1' == '  1');   // bool(true) どのバージョンでも true
var_dump('0' == '0e0');   // bool(true)
var_dump('0' == '0e10');  // bool(true)
var_dump('0' == '00');    // bool(true)
var_dump('0' == '0.0');   // bool(true)
var_dump('0' == '-0');    // bool(true)
var_dump('0' == '+0');    // bool(true)
var_dump('0' == '  0  '); // PHP 8.0.0 以上ならばbool(true)。PHP8.0.0 未満ならば bool(false)
var_dump('0' == '0  ');   // PHP 8.0.0 以上ならばbool(true)。PHP8.0.0 未満ならば bool(false)
var_dump('0' == '  0');   // bool(true) どのバージョンでも true

var_dump('r' == '  r');   // bool(false)
var_dump('r' == '  r  '); // bool(false)
var_dump('r' == 'r  ');   // bool(false)

 要するに文字列が数字と解釈できる時、数字を元にした数値が等しいならば true となる挙動があります。更なる特徴として文字列の頭と尻尾に空白があってもなくても文字列でなく数字として解釈されて true が返っていきます。この空白についての処理は PHP のバージョンで違いがあり、後ろの空白ありの場合 PHP8 以上ならば true 、PHP8 未満ならば false となります。

 上記例では==のみを使っていますが、これは緩やかな比較全般に現れるためin_arrayをはじめとした各種比較関数でも同様です。そんな感じで==はなかなか信用ならないやつです。基本的に===や関数の引数などで厳密な比較を使う様にするべきであり、異なる型同士の比較をしたい時はそれ用の関数を用意すべきでしょう。

<?php
// 異なる型同士の比較関数例
/**
 * string にキャストできる色々を文字列として比較することで型の違いを許しつつ比較を行う
 * PHP の引数の型は暗黙の型変換を起こすための型なので以下だけでOK
 * 
 * @param  string  $a
 * @param  string  $b
 * @return bool
 */
function loose_cmp(string $a, string $b): bool
{
    return $a === $b;
}
var_dump(loose_cmp(1, '1')); // bool(true)
var_dump(loose_cmp(1, 1));   // bool(true)
var_dump(loose_cmp(1, 1.0));   // bool(true)
// string にキャストできないと例外を吐くので実際に使うにはもっと拡張すべき
// var_dump(loose_cmp([], []));// Error

var_dump(loose_cmp('1', '01'));    // bool(false)
var_dump(loose_cmp('1', '001'));   // bool(false)
var_dump(loose_cmp('1', '1e0'));   // bool(false)
var_dump(loose_cmp('1', '  1  ')); // bool(false)
var_dump(loose_cmp('1', '1  '));   // bool(false)
var_dump(loose_cmp('1', '  1'));   // bool(false)
var_dump(loose_cmp('0', '0e0'));   // bool(false)
var_dump(loose_cmp('0', '0e10'));  // bool(false)
var_dump(loose_cmp('0', '00'));    // bool(false)
var_dump(loose_cmp('0', '0.0'));   // bool(false)
var_dump(loose_cmp('0', '-0'));    // bool(false)
var_dump(loose_cmp('0', '+0'));    // bool(false)
var_dump(loose_cmp('0', '  0  ')); // bool(false)
var_dump(loose_cmp('0', '0  '));   // bool(false)
var_dump(loose_cmp('0', '  0'));   // bool(false)

var_dump(loose_cmp('r', '  r'));   // bool(false)
var_dump(loose_cmp('r', '  r  ')); // bool(false)
var_dump(loose_cmp('r', 'r  '));   // bool(false)
>株式会社シーポイントラボ

株式会社シーポイントラボ

TEL:053-543-9889
営業時間:9:00~18:00(月〜金)
住所:〒432-8003
   静岡県浜松市中央区和地山3-1-7
   浜松イノベーションキューブ 315
※ご来社の際はインターホンで「316」をお呼びください

CTR IMG