PHPで変数などの比較をする際、おのおのが別の型同士だった場合にちょっと躓きやすい落とし穴があるのをご存知でしょうか?PHPに少しずつ慣れてきた人は、比較する時に起こる型変換のルールを知っておくと未然にミスが防げたりするかも知れません。

まずは簡単に。以下のスクリプトを実行した際の表示内容はどうなるでしょう?

<?php
    $foo 
"test";

    if (
$foo == 0) {
        print 
"true";
    } else {
        print 
"false";
    }
?>

「true」と答えた方は、今回のTipsの趣旨は既にご理解なさっている方です。今回のTipsはご確認程度で見てもらえればと思います。もし「false」と答えた方は、是非今回の落とし穴を知っていって下さい。ちなみに上のスクリプトの実行結果では「true」と表示されます。

では何故こうなるのでしょう?

その答えは、比較部分にあります。

上のスクリプトでは、$fooに代入されている文字列 'test' と整数の 0 を比較しています。型的に言えば、$fooは文字列のstring、0は整数のintegerです。PHPでは以下のルールがあります。

整数値を文字列と比較する際、文字列が数値に変換されます。

PHPマニュアル:比較演算子

さて、ここで言う「数値に変換される」という部分が問題です。詳しいルールは以下の参考URLからご覧いただくとしまして、今回関係する部分を大雑把に書きますと

「文字列の最初の部分が、有効な数値データで始まるもの以外は0となる」

となります。

PHPマニュアル:文字列の変換

"test" という文字列は、最初の部分が英文字の t ……すなわち数字としては有効では無いので実際に比較する際には 0 として扱われるのです。

比較時のこの決まりを知らないと、意図していなかった動きをする場合が出てきます。マニュアル内でもswitch文の例が挙げられていますが

<?php
    $foo 
"test";

    switch (
$foo) {
        case 
0:
            print 
'$fooは 0 です。';
            break;
        case 
"test":
            print 
'$fooは test です。';
            break;
        default:
            print 
'$fooは 0 でも test でもありません。';
    }
?>

最初に$fooに"test"という文字列を代入します。

「$fooは test です。」

と表示される事を意図してこのようにプログラムコードを書いたとしても、実際には

「$fooは 0 です。」

と表示されます。

文字列と整数を比較しているため、文字列が数値に変換され、0として扱われるためです。

一方、

case 0:

と書いている部分を

case '0':

などと書くと、これは「文字列」の 0 を示すため、文字列と文字列の比較が行われます。

この時、比較する型が一緒のため数値に変換されるという事は無く、純粋にそのまま比較が行われるためこの部分では一致せず、次の「 case "test": 」の所で真になり「$fooは test です。」と表示されます。

もう一つ同じような例を示します。

<?php
    $ary 
= array(012);

    
$foo "test";

    if (
in_array($foo$ary)) {
        print 
"発見!";
    } else {
        print 
"見つかりませんでした…";
    }
?>

in_array関数は、配列に値があるかチェックする関数です。上の例では test という文字列が $ary の中に値として存在するかチェックしています。

普通に考えれば「見つかりませんでした…」と表示したいハズなのですが実際に動かしてみればわかりますが「発見!」と表示されてしまいます。配列の中に整数の 0 があるため、数値変換された際に0になる文字列はこぞって引っかかってしまう事になります。

余談ですが、このin_array関数もそうですがいくつかの関数は、引数を追加して指定する事で比較時に「型」も確認します。この場合、完全に型までも一緒でなければいけなくなり、判定を厳格にする事ができます。

以下、型も比較する例です。

<?php
    $ary 
= array(012);

    
$foo "test";

    if (
in_array($foo$arytrue)) {
        print 
"発見!";
    } else {
        print 
"見つかりませんでした…";
    }
?>

このようにすると実行結果の出力は「見つかりませんでした…」となります。



(アシアル 古見澤宏)


この記事は、アシアルが運営するPHP開発者のためのポータル&コミュニティサイト「PHPプロ!」で毎週配信しているPHP・TIPSメーリングリストを再録したものです。
同サイトでは、他にもPHP最新ニュースや、困ったときのQ&A掲示板、初心者向けのPHP講座など、PHP開発者をサポートする情報を掲載しています。