「マルチバイト安全な文字数取得」とは何か
まず前提として、PHP の文字列は「バイト列」です。strlen() は「文字数」ではなく「バイト数」を返します。ここが最初の落とし穴です。
UTF-8 で日本語を扱うとき、1文字が 3 バイトになることが多いので、
「5文字なのに 15 と返ってくる」といった現象が起きます。
これを避けて、「人間が数える意味での“文字数”」を正しく数えるのが「マルチバイト安全な文字数取得」です。
strlen() と mb_strlen() の違いを体感する
strlen() は「バイト数」を返す
まずは失敗例から見てみましょう。
$str = "こんにちは";
echo strlen($str); // 15(UTF-8 の場合)
PHP「こんにちは」は 5 文字ですが、strlen() は 15 を返します。
UTF-8 では日本語 1 文字が 3 バイトなので、5 × 3 = 15 という計算になっているわけです。
英数字だけなら 1 文字 = 1 バイトなので問題になりにくいのですが、
日本語・中国語・絵文字などを扱うときには、strlen() では「人間の感覚とズレた値」になってしまいます。
mb_strlen() は「文字数」を返す
そこで登場するのが mb_strlen() です。
$str = "こんにちは";
echo mb_strlen($str, 'UTF-8'); // 5
PHPmb_strlen() は、指定したエンコーディングに従って「文字数」を数えてくれます。
UTF-8 であれば、日本語 1 文字も英字 1 文字も「1」としてカウントされます。
ここで重要なのは、
strlen()→ バイト数mb_strlen()→ 文字数(エンコーディングを考慮)
という役割の違いを、はっきり頭の中で分けておくことです。
mb_strlen() の基本的な使い方
シグネチャとパラメータ
mb_strlen() の定義はこうなっています。
int mb_strlen(string $string, ?string $encoding = null)
PHP第1引数が対象の文字列、第2引数がエンコーディングです。
$str = "こんにちは";
$len = mb_strlen($str, 'UTF-8');
echo $len; // 5
PHP第2引数のエンコーディングを省略すると、「内部エンコーディング」が使われますが、
実務では基本的に 'UTF-8' を明示することを強くおすすめします。
理由はシンプルで、「プロジェクト全体が UTF-8 前提で動いている」ことがほとんどだからです。
明示しておけば、「設定の違いで挙動が変わる」という事故を防げます。
mbstring 拡張が有効であること
mb_strlen() を使うには、PHP の mbstring 拡張が有効になっている必要があります。
最近の環境では最初から有効なことが多いですが、もし「関数が未定義」と怒られたら、
PHP の設定(拡張モジュール)を確認する必要があります。
実務での具体的なシチュエーション例
例題1:入力文字数の制限(バリデーション)
よくあるのが、「プロフィールの自己紹介は 200 文字まで」といった制限です。
$bio = $_POST['bio'] ?? '';
$len = mb_strlen($bio, 'UTF-8');
if ($len > 200) {
$error = "自己紹介は200文字以内で入力してください。(現在:{$len}文字)";
}
PHPここで strlen() を使ってしまうと、日本語が混ざった瞬間に「バイト数」で判定されてしまい、
ユーザーの感覚とズレたエラーメッセージになります。
「ユーザーが見ている“文字数”」で制限したいときは、必ず mb_strlen() を使うべきです。
例題2:一覧用に「タイトルの長さ」をチェックする
記事タイトルなどで、「長すぎるタイトルはレイアウトを崩すから、30文字までにしたい」というケース。
$title = $_POST['title'] ?? '';
if (mb_strlen($title, 'UTF-8') > 30) {
$error = "タイトルは30文字以内で入力してください。";
}
PHPここでも、英語だけなら strlen() でもたまたま動きますが、
日本語が混ざった瞬間に破綻します。
もう一歩踏み込む:エンコーディングと「何を 1 文字とみなすか」
エンコーディングを間違えると結果も狂う
mb_strlen() は「指定したエンコーディングに従って」文字数を数えます。
例えば、実際の文字列が UTF-8 なのに、誤って 'SJIS' を指定すると、
正しく数えられないどころか、場合によってはエラーや文字化けの原因になります。
だからこそ、
- アプリ全体の文字コードは UTF-8 に統一する
mb_strlen()には'UTF-8'を明示する
というセットを「お約束」にしてしまうのが、実務では一番安全です。
「見た目の 1 文字」と「コード上の 1 文字」がズレるケース
さらに細かい話をすると、絵文字や結合文字(アクセント付き文字など)では、
「見た目 1 文字」が複数のコードポイントで構成されることがあります。
このレベルまで厳密に「見た目の 1 文字」を数えたい場合は、mb_strlen() ではなく grapheme_strlen() などを検討することになります。
ただし、一般的な日本語 Web システムでは、まずは mb_strlen() を使うだけで十分なことがほとんどです。
「絵文字を含めた完全な“見た目の 1 文字”カウント」は、もう一段高度な世界だと覚えておけば OK です。
実務ユーティリティとしてまとめる
共通関数としてラップしておく
毎回 mb_strlen($str, 'UTF-8') と書くのが面倒なら、
プロジェクト共通のユーティリティ関数としてラップしておくと便利です。
/**
* マルチバイト安全な文字数取得(UTF-8 前提)
*/
function mb_length(string $str): int
{
return mb_strlen($str, 'UTF-8');
}
PHP使い方はこうなります。
$len = mb_length("こんにちは"); // 5
if ($len > 200) {
// バリデーションエラー
}
PHP「このプロジェクトでは文字数は全部 mb_length() で数える」というルールにしておけば、strlen() をうっかり混ぜてしまう事故を防げます。
strlen() を使う場面は「バイト数が欲しいとき」だけに限定する
逆に、strlen() を使うのは、
- バイナリデータの長さを知りたいとき
- プロトコル上「バイト数」で長さを送る必要があるとき
など、「バイト数が欲しい」と明確に分かっている場面だけに絞るとよいです。
まとめ:今日からの「文字数カウント」の基準
ここまでをギュッとまとめると、実務での基準はこうなります。
- 日本語を含む「人間が読む文字列」の文字数を数えたい
→mb_strlen($str, 'UTF-8')を使う - その呼び出しを簡単にするために、
mb_length()のようなラッパー関数を用意してもよい strlen()は「バイト数が欲しいときだけ」に限定する

