preg_replace_callback関数には、「&$count」というパラメータがある。
「count
パラメータを指定した場合は、置換を行った回数がここに格納されます。」とのこと。
このパラメータに助けられた話。
やりたいこと
HTMLソースから img タグを抽出し、src 属性の変更と class 属性の変更をする
class属性が存在しない場合は新たに追加する
preg_replace_callback関数で課題に感じたこと
preg_replace_callback関数は、マッチした場合は、コールバック関数が呼び出されるが、マッチしない場合は、コールバック関数は呼び出されず、置換対象となる文字列がそのまま返される。
そのため、コールバック関数が呼び出されないと、class属性が存在しない場合に新たに追加する処理ができない。
既に設定されているclass属性にlazyを追記することしかできない。。
$modImage = preg_replace_callback('/class=[\"\']([^\s]*)[\"\']/i', function($class) {
$class[1] .= ' lazy';
return 'class="' . $class[1] . '"';
}, $modImage);
preg_replace_callback関数の挙動について
preg_replace_callback関数は、正規表現を使って、置換対象を全て検索し、コールバック関数を使用して置換を行う関数。
置換対象が2つあると、2回コールバック関数がよばれる動作となっている。
そして、返り値は、マッチした場合とマッチしない場合で違っている。
マッチした場合は、コールバック関数の結果を返し、マッチしない場合は、置換対象となる文字列がそのまま返される。
count
パラメータの発見
ドキュメントを見ていると、count
パラメータなるものがあり、
これを使えば、コールバック関数が呼び出されたかどうかがわかることに気づいた。
そういうことで以下のように$matchCountをチェックすることで、class属性がない場合の処理を組むことができた。
$modImage = preg_replace_callback('/class=[\"\']([^\s]*)[\"\']/i', function($class) {
$class[1] .= ' lazy';
return 'class="' . $class[1] . '"';
}, $modImage, 1, $matchCount);
// class属性がないため、class属性を追加
if (!$matchCount) {
$modImage = preg_replace('/<img /i', '<img class="lazy" ', $modImage);
}
参考リンク
- PHP: preg_replace_callback – Manual
https://www.php.net/manual/ja/function.preg-replace-callback.php