はじめに
PHPで正規表現による文字列置換を行う際、複数のパターンを処理したい場面はよくありますよね。従来はpreg_replace_callbackを何度も呼び出す必要がありましたが、PHP 7.0以降ではpreg_replace_callback_array関数を使うことで、複数のパターンとコールバック関数をまとめて処理できるようになりました。
この記事では、preg_replace_callback_arrayの基本から実践的な使い方まで、サンプルコードを交えながら詳しく解説します。
preg_replace_callback_arrayとは?
preg_replace_callback_arrayは、複数の正規表現パターンとそれぞれに対応するコールバック関数を配列で指定し、文字列置換を一度に実行できる関数です。
基本構文
preg_replace_callback_array(
    array $pattern_callback_array,
    string|array $subject,
    int $limit = -1,
    int &$count = null,
    int $flags = 0
): string|array|nullパラメータ
- $pattern_callback_array: パターンとコールバック関数の連想配列
- $subject: 検索・置換対象の文字列(または配列)
- $limit: 各パターンの最大置換回数(デフォルト: -1=無制限)
- $count: 実行された置換の総数を格納する変数(参照渡し)
- $flags: オプションフラグ
基本的な使い方
シンプルな例
HTMLタグを一度に処理する例を見てみましょう。
<?php
$text = "こんにちは、<b>太字</b>と<i>斜体</i>のテキストです。";
$result = preg_replace_callback_array(
    [
        // <b>タグを**で囲む
        '/<b>(.*?)<\/b>/' => function($matches) {
            return '**' . $matches[1] . '**';
        },
        // <i>タグを__で囲む
        '/<i>(.*?)<\/i>/' => function($matches) {
            return '__' . $matches[1] . '__';
        }
    ],
    $text
);
echo $result;
// 出力: こんにちは、**太字**と__斜体__のテキストです。
?>実践的な使用例
例1: マークダウン風のテキスト変換
<?php
$markdown = "見出しは #タイトル# で、リンクは [リンク文字](URL) で表現します。";
$html = preg_replace_callback_array(
    [
        // #見出し# → <h2>見出し</h2>
        '/#(.*?)#/' => function($m) {
            return '<h2>' . htmlspecialchars($m[1]) . '</h2>';
        },
        // [テキスト](URL) → <a href="URL">テキスト</a>
        '/\[(.*?)\]\((.*?)\)/' => function($m) {
            return '<a href="' . htmlspecialchars($m[2]) . '">' 
                   . htmlspecialchars($m[1]) . '</a>';
        }
    ],
    $markdown
);
echo $html;
?>例2: 個人情報のマスキング
<?php
$text = "電話: 090-1234-5678、メール: example@test.com";
$masked = preg_replace_callback_array(
    [
        // 電話番号をマスク
        '/(\d{3})-(\d{4})-(\d{4})/' => function($m) {
            return $m[1] . '-****-' . $m[3];
        },
        // メールアドレスをマスク
        '/([a-zA-Z0-9._%+-]+)@([a-zA-Z0-9.-]+\.[a-zA-Z]{2,})/' => function($m) {
            return substr($m[1], 0, 2) . '***@' . $m[2];
        }
    ],
    $text
);
echo $masked;
// 出力: 電話: 090-****-5678、メール: ex***@test.com
?>例3: 価格表示の整形
<?php
$text = "商品Aは1000円、商品Bは2500円、商品Cは10000円です。";
$formatted = preg_replace_callback_array(
    [
        // 4桁以上の数字をカンマ区切りに
        '/(\d)(?=(\d{3})+(?!\d))/' => function($m) {
            return $m[1] . ',';
        },
        // 数字+円を装飾
        '/(\d[\d,]*)円/' => function($m) {
            return '<span class="price">¥' . $m[1] . '</span>';
        }
    ],
    $text
);
echo $formatted;
// 出力: 商品Aは<span class="price">¥1,000</span>、...
?>preg_replace_callbackとの違い
従来の方法(preg_replace_callback)
<?php
$text = "Hello World";
$text = preg_replace_callback('/Hello/', function($m) {
    return 'Hi';
}, $text);
$text = preg_replace_callback('/World/', function($m) {
    return 'PHP';
}, $text);
?>preg_replace_callback_arrayを使った方法
<?php
$text = "Hello World";
$text = preg_replace_callback_array([
    '/Hello/' => fn($m) => 'Hi',
    '/World/' => fn($m) => 'PHP'
], $text);
?>メリット:
- コードがスッキリして読みやすい
- パターンとコールバックの対応が明確
- パフォーマンスが若干向上(内部で最適化される)
置換回数の制限と確認
<?php
$text = "cat cat dog dog bird bird";
$result = preg_replace_callback_array(
    [
        '/cat/' => fn($m) => '猫',
        '/dog/' => fn($m) => '犬',
        '/bird/' => fn($m) => '鳥'
    ],
    $text,
    1,  // 各パターンで最大1回まで置換
    $count  // 置換回数を取得
);
echo $result . "\n";
// 出力: 猫 cat 犬 dog 鳥 bird
echo "置換回数: {$count}回\n";
// 出力: 置換回数: 3回
?>よくある使用例とパターン
URLの自動リンク化
<?php
function autoLink($text) {
    return preg_replace_callback_array([
        // HTTPSリンク
        '/(https?:\/\/[^\s]+)/' => function($m) {
            return '<a href="' . $m[1] . '" target="_blank">' 
                   . $m[1] . '</a>';
        },
        // メールアドレス
        '/([a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,})/' => function($m) {
            return '<a href="mailto:' . $m[1] . '">' . $m[1] . '</a>';
        }
    ], $text);
}
$text = "お問い合わせはinfo@example.comまで。詳細はhttps://example.comをご覧ください。";
echo autoLink($text);
?>注意点とベストプラクティス
1. パターンの実行順序
配列の順序でパターンが適用されるため、順序が重要な場合は注意が必要です。
<?php
// 悪い例:先に広範なパターンを適用
$bad = preg_replace_callback_array([
    '/\d+/' => fn($m) => '[数字]',  // すべての数字
    '/\d{3}-\d{4}/' => fn($m) => '[郵便番号]'  // 届かない!
], '郵便番号は123-4567です');
// 良い例:具体的なパターンを先に
$good = preg_replace_callback_array([
    '/\d{3}-\d{4}/' => fn($m) => '[郵便番号]',  // 先に
    '/\d+/' => fn($m) => '[数字]'
], '郵便番号は123-4567です');
?>2. エスケープ処理
ユーザー入力を扱う場合は必ずエスケープを行いましょう。
<?php
$result = preg_replace_callback_array([
    '/{{(.*?)}}/' => function($m) {
        // XSS対策
        return htmlspecialchars($m[1], ENT_QUOTES, 'UTF-8');
    }
], $text);
?>3. パフォーマンスの考慮
大量のテキスト処理では、不要な処理を避けましょう。
<?php
// 置換が必要かチェックしてから実行
if (preg_match('/<[^>]+>/', $text)) {
    $text = preg_replace_callback_array([...], $text);
}
?>まとめ
preg_replace_callback_arrayは、複数の正規表現パターンを効率的に処理できる強力な関数です。
主な特徴:
- ✅ 複数パターンを一度に処理できる
- ✅ コードの可読性が向上する
- ✅ PHP 7.0以降で使用可能
- ✅ 柔軟なコールバック処理が可能
複雑なテキスト処理を行う際は、ぜひこの関数を活用してみてください!
参考リンク
この記事が役に立ったら、ぜひシェアしてください!
 
  
  
  
  