【PHP】strcmpで文字列を比較する方法|戻り値の意味とif判定の落とし穴

PHPの strcmp() は2つの文字列を比較し、結果を整数で返す関数です。大小関係(並び順)の判定に使いますが、if (strcmp($a, $b)) と書くと判定が逆になるという有名な落とし穴があります。この記事では戻り値の正しい読み方と、用途に応じた使い分けを解説します。

この記事の結論:strcmp()等しいと0$str1が小さいと負・大きいと正を返します。等しいかを判定するなら strcmp($a, $b) === 0、あるいは単純な一致なら $a === $b を使うのが明快です。
スポンサーリンク

strcmpの戻り値の意味

関係 戻り値
$str1 が $str2 より小さい 負の整数
$str1 と $str2 が等しい 0
$str1 が $str2 より大きい 正の整数
基本の使い方
<?php
$result = strcmp("apple", "banana");

if ($result < 0) {
    echo "apple の方が前";   // これが実行される
} elseif ($result > 0) {
    echo "banana の方が前";
} else {
    echo "等しい";
}
戻り値は「負・0・正」であり、必ずしも -1 / 0 / 1 とは限りません。値の正負だけを見て判定し、「== -1」「== 1」のような厳密な値比較は避けてください。

注意:if (strcmp(…)) は判定が逆になる

最も多い間違いがこれです。「等しいかどうか」を if (strcmp($a, $b)) で判定しようとすると、意図と逆の結果になります。等しいときの戻り値は 0falsy(偽)だからです。

NG / OK: 等価判定
<?php
// NG: 等しいときに 0(偽)なので、if は「違うとき」に真になる
if (strcmp("apple", "apple")) {
    echo "違う";  // 実行されない
} else {
    echo "同じ";  // ← こちらが実行される(紛らわしい)
}

// OK: 0 と明示的に比較する
if (strcmp("apple", "apple") === 0) {
    echo "同じ"; // 正しく判定
}
単に「文字列が一致するか」を見たいだけなら、strcmp ではなく=== を使いましょう。if ($a === $b) のほうが読みやすく、意図も明確です。strcmp大小(並び順)が必要なときに使う関数です。

大文字・小文字を区別しない比較(strcasecmp)

strcmp() は大文字・小文字を区別します。区別せずに比較したいときは strcasecmp() を使います。

strcasecmpで大小文字を無視
<?php
var_dump(strcmp("Apple", "apple"));      // 0 以外(区別する → 不一致)
var_dump(strcasecmp("Apple", "apple"));  // 0(区別しない → 一致)

usortの比較関数として使う

strcmp() は「負・0・正」を返すため、並べ替えの比較関数(comparator)にそのまま使えるのが便利です。文字列の配列をアルファベット順に並べ替えられます。

usortで文字列をソート
<?php
$fruits = ["banana", "apple", "cherry"];

usort($fruits, fn($a, $b) => strcmp($a, $b));
print_r($fruits); // apple, banana, cherry

// 逆順なら引数を入れ替える
usort($fruits, fn($a, $b) => strcmp($b, $a));
連想配列の値での並べ替えや、より複雑な比較関数は連想配列の値で並び替える方法(usortとカスタム比較関数)で詳しく解説しています。

補足:バイト比較と先頭N文字の比較

strcmp()バイト単位で比較します。ASCIIの英数字なら辞書順になりますが、日本語などマルチバイト文字の「五十音順」にはなりません。また、先頭からN文字だけ比較したい場合は strncmp() を使います。

strncmpで先頭N文字を比較
<?php
// 先頭3文字だけ比較
var_dump(strncmp("apple", "application", 3)); // 0("app" が一致)

よくある質問(FAQ)

Qif (strcmp($a, $b)) で等しいか判定できますか?
Aできません。むしろ逆になります。等しいときの戻り値は 0(偽)なので、その if は「違うとき」に真になります。等価判定は strcmp($a, $b) === 0、もしくは単純に $a === $b を使ってください。
Q文字列が一致するか調べるだけなら何を使う?
A=== が最も明快で高速です(if ($a === $b))。strcmp は大小(並び順)が必要な場面で使う関数です。
Qstrcmpの戻り値は必ず-1か1ですか?
Aいいえ。「負・0・正」であって、絶対値が1とは限りません。正負だけで判定し、=== -1 のような厳密な値比較は避けてください。
Q大文字小文字を無視して比較したいです。
Astrcasecmp() を使います。strcmp() は大文字小文字を区別しますが、strcasecmp() は区別しません。

まとめ

strcmpのポイントを整理します。

  • 戻り値は等しいと0・小さいと負・大きいと正(-1/1とは限らない)
  • if (strcmp(...)) は判定が逆になる → 等価は === 0
  • 単純な一致確認は === が明快
  • 大小文字を無視するなら strcasecmp()
  • 「負・0・正」を返すので usort の比較関数に最適

関連として、usortで連想配列を並び替える方法if文による条件分岐switch文の使い方もあわせて読むと、PHPの比較・分岐に強くなれます。