PHPでWebプログラムすることのある僕がstrcmp関数を使う100の理由(ぉ

==の代わりにstrcmp関数で比較すると、float型とarray型を扱う場合に==を使うのとは別の問題が発生することを示しました。

そんな型が来るならstrcmp使わないよ、という意見もあるとは思いますが、来る型がわかっているなら===を使えばいいと思うんですよね。strcmpを使いたい状況が僕にはわかりません。何にせよ、「安全な==」として使うにはstring型へのキャストを熟知している必要があると思いますよ、というのが本記事の主張です。strcmpは文字列同士の大小比較にしか使えないと僕は思います。

PHPで==の代わりにstrcmp関数を使うことによる問題点 - hnwの日記

記事の主張はまったくごもっともで確かにその通りなのですが、それでも僕がstrcmp関数を使う理由はint型とstring型で比較したいからなんですよねー。

実際に関数を作るとき殆ど多くの関数において、float型を前提に作ることはまずないと思うんです。

だって例えば与えられた引数に対して正規表現でチェックする処理とかよくやるでしょ?

<?php

function check ( $data ) {
    if ( preg_match('/^[0-9]+$/',$data)  ) {
        print "ok\n";
    }
    else {
        print "ng\n";
    }
}

こんなのね。

この関数はint型でもstring型でもうまく動きます。でもfloat型だと値が大きい場合にうまくいきません。

<?php

check(1234);      // ok
check('567890');  // ok

check(pow(2,52)); // ng

でこれをfloat型でもうまく動くようにですよ、対応してもいいんですが、それで得られるメリットって殆どないような気がするんですよ。

<?php

function check ( $data ) {

    // float型に対応するぜ!
    if ( is_float($data) ) $data = sprintf("%.0f",$data);

    if ( preg_match('/^[0-9]+$/',$data)  ) {
        print "ok\n";
    }
    else {
        print "ng\n";
    }
}

check(pow(2,52)); // ok

これを仕込んだところで殆ど使われる可能性はありません。

何故なら実際の業務でプログラミングする場合、Webページからの入力された値を扱うことが殆どなので基本的にはstring型しか来ないからです。

でさらに、プログラム内部から直接値を渡すときでも、例えば性別フラグ0か1を許可したいような場合とか、殆どint型の範囲内で収まるような数値しか扱わないので基本的には関数側はint型とstring型さえサポートできていればモウマンタイなんですよね。だってfloat型の大きな数値がきてもそもそも性別は0か1だけなので条件に合わないのですから問題ないですし。

===を使うことを主眼においた場合、結局のところ関数の呼び出し側が面倒になることが多くなるように思います。

<?php

function sex_string_only ( $flag ) {
    if ( !is_string($flag) ) {
        // error!
    }
    
    if ( $flag === '0' ) {
        // 男性
    }
    else if ( $flag === '1' ) {
        // 女性
    }
    else {
        // error
    }
}

function sex_int_string ( $flag ) {
    if ( strcmp($flag,'0') == 0 ) {
        // 男性
    }
    else if ( strcmp($flag,'1') == 0 ) {
        // 女性
    }
    else {
        // error
    }
}

$flag = 1;

sex_string_only($flag);         // error
sex_string_only((string)$flag); // 女性

sex_int_string($flag);         // 女性
sex_int_string((string)$flag); // 女性

sex_string_only関数の処理がエラーになるのは面倒じゃないですか?結局自分でstring型にキャストしないとこの関数は使えないんですよね。だったら初めから関数側が両方対応してる方が楽でしょう。

この関数では0や1しか受け付けないのでfloat型やarray型による間違ったケースが絶対に通らないのでそういう場合はstrcmp使っていいと思うんですよ。

因みにid:hnwさんが言っている

strcmpを使いたい状況が僕にはわかりません。何にせよ、「安全な==」として使うにはstring型へのキャストを熟知している必要があると思いますよ

の後半には激しく同意します。

ですがひとつ付け足すなら「===」使う場合でもstring型へのキャストを熟知している必要があると思います。

何故ならsex_string_only関数を正しく呼び出そうと思ったら自分でstring型へキャストしないとダメだからです。

単純に言えば、strcmpを使用した関数を作る場合はその関数の製作者がstring型へのキャストに関して知っておく必要があります。

一方、===を使用した関数を作る場合はその関数の使用者がstring型へのキャストに関して知っておく必要がある、という感じになりますかね。ならない?ごめんちゃ。

どっちがいいのかは、んー・・・・・・・・。ってかそもそもキャストの挙動くらいPHPプログラマならある程度わかってないとダメ!っていう結論がキレイですよねーよねーよねー・・・・・。



とはいえ、僕も15桁以上のfloat型の問題や「-0.0」の問題なんかはid:hnwさんの記事を読んで初めて知ったことなのでPHPでプログラムを組むことがある身としては失格でございますです。猛反orz。