mb_strlen — マルチバイト対応の文字数(コードポイント数)を取得

PHP
  • カテゴリ: PHP
  • 対応バージョン: Laravel 11/12・PHP 8.2(※指定がなかったため既定値を採用)
  • 名前空間 / FQCN / コマンド: 関数 mb_strlen(string $string, ?string $encoding = null): int
  • 関連: strlen / mb_substr / mb_strwidth / grapheme_strlen / mb_detect_encoding
  • 変更履歴: PHP 8.0 以降、無効なエンコーディング等で ValueError を送出。8.1/8.2/8.3 で大きな仕様差分なし。

要点(TL;DR)

  • マルチバイト文字列の**文字数(コードポイント数)**を返す。
  • mb_strlen('あいう', 'UTF-8') // 3
  • 罠:
    • 見た目1文字の合成絵文字は複数カウント→ 見た目の文字数は grapheme_strlen
    • バイト数ではない(DB制限は strlen で確認)
    • ext-mbstring が必須。無効だと関数未定義。

概要

mb_strlen はマルチバイト文字列の長さを、エンコーディングを考慮してコードポイント数で返します。日本語や多言語テキストの入力長チェックに必須です。フォームバリデーションや API の文字数制限、ログの整形などで使用します。

構文 / シグネチャ

int mb_strlen(string $string, ?string $encoding = null)
  • 引数(表)
引数必須既定値説明
$stringstringなし対象の文字列
$encoding?stringnull文字エンコーディング。nullmb_internal_encoding() の設定を使用。一般に 'UTF-8' を明示指定推奨
  • 戻り値int — 文字数(コードポイント数)
  • 例外/副作用
    • TypeError(型不一致)
    • ValueError(無効なエンコーディング指定 等)
    • 必要拡張ext-mbstring(任意で grapheme_* 系は ext-intl

使用例

最小例

<?php
declare(strict_types=1);

$text = 'こんにちは';           // 5文字
echo mb_strlen($text, 'UTF-8');  // 5

// バイト数との違い
echo strlen($text);               // 15(UTF-8は1文字=3バイト)

実務例(バリデーション:見た目の文字数にも対応)

<?php
declare(strict_types=1);

// ルール: 1〜100文字(見た目の文字数で数えたい場合は grapheme_* を利用)
function lengthValid(string $s, int $min = 1, int $max = 100): bool
{
    // 見た目の文字数を優先(ext-intl が無い場合は mb_strlen をフォールバック)
    $len = function_exists('grapheme_strlen')
        ? grapheme_strlen($s)
        : mb_strlen($s, 'UTF-8');

    return $len >= $min && $len <= $max;
}

// DBの列制限が「バイト数」のときは strlen を使う例(utf8mb4 で 191バイト以内など)
function fitsBytes(string $s, int $maxBytes): bool
{
    return strlen($s) <= $maxBytes;
}

// 無効なエンコーディング指定の例外処理
try {
    $n = mb_strlen('テスト', 'INVALID-ENCODING'); // ValueError
} catch (ValueError $e) {
    error_log('エンコーディング指定が不正: ' . $e->getMessage());
}

よくある落とし穴・注意

  • 合成絵文字・ZWJ"👨‍👩‍👧‍👦" は見た目1文字でもコードポイントは複数。mb_strlen は 7 を返すことがある。見た目ベースなら grapheme_strlenext-intl)。
  • バイト数と混同しない:MySQL VARCHAR(100)バイト制限が絡む場合は strlen で確認(UTF-8 は最大4バイト/文字)。
  • 内部エンコーディングに依存しないmb_internal_encoding() によるグローバル状態は予期せぬバグの元。'UTF-8'明示指定する。
  • 拡張が無効Call to undefined function mb_strlen()ext-mbstring 未有効。環境によりインストール/有効化が必要。
  • 8.1/8.2/8.3 差分:大きな仕様変更なし(8.0 で一部エラーが ValueError に変更済み)。

代替・関連APIとの比較

  • strlen …… バイト数。プロトコル/DBのサイズ制限チェックに。
  • mb_strlen …… コードポイント数。言語学的な「文字数」カウントに。
  • grapheme_strlen …… ユーザー視点の見た目の文字数(書記素クラスタ)。UI の文字数制限・折返しに最適。
  • mb_strwidth …… 表示幅(全角=2、半角=1 的な幅)。CLI 表や桁揃えに。

テスト例(Pest)

<?php

it('counts multibyte characters', function () {
    expect(mb_strlen('あ', 'UTF-8'))->toBe(1);
    expect(mb_strlen('🍣', 'UTF-8'))->toBe(1); // 単一コードポイント絵文字
});

it('shows difference for grapheme clusters', function () {
    $family = "👨‍👩‍👧‍👦"; // 見た目1文字の家族絵文字
    expect(mb_strlen($family, 'UTF-8'))->toBeGreaterThan(1); // 例: 7
    if (function_exists('grapheme_strlen')) {
        expect(grapheme_strlen($family))->toBe(1);
    }
});

トラブルシュート(エラー別)

症状/エラー原因対処
Call to undefined function mb_strlen()ext-mbstring 未有効PHP拡張をインストール/有効化(php -m で確認)
ValueError: mb_strlen(): Argument #2 ($encoding) must be a valid encoding無効なエンコーディング名'UTF-8' を明示。mb_list_encodings() で対応一覧を確認
文字数と見た目が合わない合成絵文字・結合記号(ZWJ)grapheme_strlen を使用(ext-intl が必要)
DB保存で桁溢れバイト数制限を文字数で判定挿入前に strlen($s)バイトを確認
本番でのみ文字化け内部エンコーディング差異すべて 'UTF-8' 明示 + 入出力経路を統一

参考リンク

レン (Wren)

こんにちは。レンです。

Laravelのコードの森に住んでいる、小さな案内役です。
ルーティングの枝やクラスの影を歩きながら、コードの流れや仕組みを眺めています。

このサイトでは、Laravelの基本から実装のコツまで、開発で役立つポイントを静かに整理しています。
難しいことを増やすのではなく、コードの見通しが少し良くなるヒントを届けるのが役目です。

「この処理はどこに書くのがいいのか」
「Laravelではどう考えると整理できるのか」

そんな疑問に、小さなメモを残すような気持ちで記事を書いています。

コードを書いている途中で迷ったとき、
このサイトが少し立ち止まって整理できる場所になればうれしいです。

レン (Wren)をフォローする