文字列の比較にstrcmp使うべきか否か。(PHPの話)

過去のエントリーにPHPで==の代わりにstrcmp関数を使うことによる問題点というのを見つけたのですが、いまだに実際のソースコードにstrcmpで文字列比較を行っているパターンをよく見かけます。と、言うかやってます。

え!?俺、思いっきり使ってたよ!俺まさか情弱って思われてる?

と、ふと不安になったのでstrcmpについて考えてみました。

なぜそもそもstrcmpで文字列比較を行うようになったのか。

それはPHPの自動型変換が大きな理由になっています。

// これがtrueになるのは有名な話
var_dump("abc" == 0);
var_dump("1abc" == 1);

整数値を文字列と比較したり、比較に数値形式の文字が含まれる場合は、文字列が 数値に変換され、 数値としての比較を行います。これらのルールは、 switch 文にも適用されます。 === あるいは !== による比較では型変換は発生しません。 この場合は値だけでなく型も比較します。

引用元:PHP: 比較演算子 – Manual

ということで、文字列「”1abc”」と数値「1」の比較には”===”を使って正確に判断しましょうということになりました。

// この場合型変換は行われないのでfalse
var_dump("abc" === 0);
var_dump("1abc" === 1);

以上で問題解決!と行きたいわけですが、下記のようなことをやりたい人もいるわけです。

// この場合はfalseでいいけど。
var_dump("1a" === 1);
// これはtrueじゃなきゃヤダ。
var_dump("1" === 1);

PHPer脳でしょうか。「いちえー」は「いち」と違うけど「いち」は「いち」だろ!っていう。で、strcmpを使うとうまくいくという。

// これはfalse
var_dump(strcmp("1a", 1) === 0);
// これはtrue
var_dump(strcmp("1", 1) === 0);

なんか関数使っていると上級っぽくね?という理由で使い始めて、そのまま使い続けてしまうというパターンではないでしょうか。そしてついには、逆にstrcmpでない方がキモく感じてしまう体になってしまうのです(たぶん)。

本当のキモさはPHPのキャストではなく型が分からないことにある。

本当のキモさは、キャストによって値が丸めこまれることではなく、なんかバグが起きて → 型違いの比較が原因であることが分かって → strcmpを使ったら治って → 「わーい!やったー!」的な考え方にあると思います。

strcmpは文字列の比較を行う関数です。文字列か数値かわからないものを比較しなければいけない状況そのものが問題なのです。計算結果のような確実に数値型のものをstrcmpに突っ込んでいたらさすがに問題外ですが。

// こんなことやるやついるのか??
$val = 1;
if(strcmp(++$val, 2) === 0){}

僕の場合、「これは完全なる文字列の比較だオラァ!」って時につかいます。
実際にフォームからのリクエストやDBから取得した値はは文字列型で取得されますし、コード値の比較ではよく使っています。

// こんな感じで
define('MALE_CODE',   '01');
define('FEMALE_CODE', '02');
// 男性の場合
if(strcmp($code, MALE_CODE) === 0){}
// 女性の場合
if(strcmp($code, FEMALE_CODE) === 0){}

この場合も”===”でもいいんですけどね。そう考えるとstrcmpでないといけない理由なんて確かにどこにもないです。

結論、どっちでもいい。

strcmpだろうが、”===”だろうが文字列型と数値型を比較しなければいけないということが、そのプログラム自体に他に何かバグが潜んでいると考えるべきでしょう。

っていうかstrcmpに数値型を入れている時点で、「文字列の比較にstrcmpは適切か」という議題をそもそも丸めこんでしまっているような気がします。

ま、なんにせよルールを決めてそれに従いコーディングするのが善で、何のルールもなく文字列の比較に”strcmp”や”===”が混在しているのが悪ですね。

strcmpを使っている現場では使うべきだし、”===”しかダメ!って言う現場では使わないべき、そんな感覚でいんじゃないでしょうか。

ちなみに

ちなみにC言語では文字列の比較にはstrcmp関数を使います。

以下のように比較を行った場合、ポインタ同士の比較になってしまい期待通りの結果は一生得られません。

char c[] = "abc";
if(c == "abc")
{
    printf('1');
}
else
{
    printf('0');
}
実行結果
0

では期待通りの結果を得るためにはどのようにすればよいか。
ポインタのアドレスに格納されている文字列の比較を行うのがC言語のstrcmp関数です。

char c[] = "abc";
if(strcmp(c, "abc") == 0)
{
    printf('1');
}
else
{
    printf('0');
}
実行結果
1

「文字列の比較はstrcmp関数を使う」というのをPHPで広めたのはC言語出身エンジニアではないかとひそかに思っています。

コメントを残す