str_replaceに配列を渡して複数置換する
str_replace とは、文字列中の検索語を置換語に置き換える関数です。検索と置換の両方に配列を渡すと、複数の置換をまとめて行えます。
配列を渡してまとめて置換
str_replace は単一の置換だけでなく、検索と置換の両方に配列を渡せます。テンプレートの一括置換や、記号の正規化をまとめてやりたいときに便利です。検索配列と置換配列を同じ添字同士で対応させて処理してくれます。
$search = ['{name}', '{price}'];
$replace = ['田中さん', '1,200円'];
$tpl = 'こんにちは{name}、合計は{price}です';
echo str_replace($search, $replace, $tpl);
// こんにちは田中さん、合計は1,200円です
置換配列の要素が足りない場合は、対応する検索語は空文字に置き換えられます。数が合っているか、地味に気をつけたいところです。
第4引数countで回数を受け取る
第4引数に変数を参照で渡すと、置換が何回行われたかが入ります。「置換が発生したかどうか」で分岐したいときや、想定件数と合っているかをチェックしたいときに使えます。
$text = 'a-b-c-d';
str_replace('-', '_', $text, $count);
echo $count; // 3
// 置換が起きたかで分岐
$result = str_replace('禁止語', '***', $comment, $hit);
if ($hit > 0) {
// NGワードが含まれていた
}
順序の罠と、連鎖置換に注意
一番ハマるのがこれです。str_replace は検索配列を先頭から順に処理するので、前の置換結果があとの検索にまた引っかかる「連鎖」が起きます。たとえば a を b に、b を c に置換すると、最初に b になった文字がさらに c まで変わってしまいます。
// 意図しない連鎖
echo str_replace(['a', 'b'], ['b', 'c'], 'a');
// "c" になる(a→b→c と二段で変わる)
// エスケープ処理で特にやりがち
// '&' を '&' にした後に他を処理する順番が重要
$s = str_replace(
['&', '<', '>'],
['&', '<', '>'],
$raw
);
だから HTML エスケープの類では「& を最初に処理する」のが鉄則になっています。置換対象と置換後の文字が重なりそうなら、順序を吟味するか、一度きりの置換が保証される strtr を検討したほうが安全な場面もあると思います。
まとめ
str_replace は配列渡しでまとめて置換できるのが強みですが、検索配列の順に処理されるせいで連鎖置換という落とし穴があります。count 引数で回数を拾えること、順序が結果を左右すること、この2点を意識しておけば、テンプレート展開やエスケープで痛い目を見ずに済むと思います。
よくある質問
Q. 何回置換されたか知りたいです。
A. 第4引数に変数を参照で渡すと、置換された回数が入ります。置換が起きたかどうかで分岐したいときにも使えます。
Q. 配列渡しで気をつけることは?
A. 検索配列を先頭から順に処理するので、前の置換結果が後の検索にまた引っかかる連鎖が起きます。HTML エスケープで & を最初に処理するのは、このためです。
Q. 連鎖置換を避けたいです。
A. 置換対象と置換後の文字が重なりそうなら、一度きりの置換が保証される strtr の利用を検討すると安全な場面があります。