strtr vs. str_replace

Когда-то я любил просматривать слайды по теме ускорения ПХП. Теперь это стало слишком скучно — основные промахи в этом плане команда его разработчиков устранила, а остальные принципы те же, что и в других языках.

Кроме того, часто выход какой-то новой версии обесценивал результаты большинства исследований в этой области. Недавний выход «семёрки» с блеском это продемонстрировал.

Среди подобных текстов есть и вредные. Речь об одном из них и пойдёт. Впервые на сравнение производительности функций str_replace и strtr (с одним параметром) я наткнулся очень много лет назад, тогда с ним разобрался и тему для себя закрыл.

Но такие исследования возникают постоянно, а авторы совершенно не утруждают себя ответом на вопрос «почему», так что я решил написать этот небольшой текст.

Итак, есть две функции, которые ведут себя очень похожим образом — заменяют в строке что-то одно на что-то другое. Велик соблазн объявить их совершенно одинаковыми (что часто и происходит), тем более их описание в руководстве по языку не акцентирует внимание на различиях. Но они есть, и очень важные.

Обратите внимание на этот код:

$r = ['xo' => 'xaxе', 'xa' => 'xo'];
$s = 'xoxo';

var_dump(str_replace(array_keys($r), array_values($r), $s)); // xoxеxoxе
var_dump(strtr($s, $r)); // xaxеxaxе

Очевидно результаты разные, но почему? Потому что str_replace делает замену «в лоб» — проходя строку несколько раз, по числу заданных замен. Поэтому получается «xoxo» → «xaxexaxe» → «xoxexoxe».

Функция strtr куда более хитрая, но работает более… естественным что ли образом — т. е. так как обычно человек ждёт от функции множественной замены. Самое главное — в сделанной замене она уже ничего не заменяет.

Есть и другое отличие:

$r = ['user1' => 'one', 'user11' => 'eleven'];
$s = 'user11';

var_dump(str_replace(array_keys($r), array_values($r), $s)); // one1
var_dump(strtr($s, $r)); // eleven

Мой пример выглядит несколько искусственно, но это часть случая из жизни, правда очень упрощённого. Тут беда в том, что str_replace применяет свои замены слева направо — в порядке перечисления, тогда как strtr сначала сортирует их по длине.

Как видите, эти функции совершенно разные по своему действию и сравнивать по производительности их просто некорректно.

3 комментария

В последний раз о Кандауровых

О своих предках Кандауровых (или Кондауровых) я писал несколько раз ([1], [2], [3]), сегодня, видимо, напишу в последний, чтобы поставить символическую точку, так как источники кончились, продвижения дальше не будет.

Кандауровы (38.96КиБ)

Эта ветка выделяется тем, что она у меня рекордсменка — самый дальний предок жил аж в 16-м веке. Точных дат у меня нет, но по понятным ограничениям Данила Кандауров не мог родится в 17-м веке.

Я считаю, это очень хороший результат. Именитых предков у меня нет и в этой ветке очень помог затяжной судебный процесс, который попал во множество документов того времени и, как фонарём во тьме веков, выхватил несколько поколений Кондауровых. Едва ли так повезёт ещё раз.

15 комментариев