preg_replace() /e

Горбушка

Ищу её...
Регистрация
2 Май 2008
Сообщения
3.444
Реакции
2.524
Есть вот такой код... Он заменяет всякие {date=d.m.Y} на значение даты в бд.
PHP:
$text = preg_replace ( "#\{date=(.+?)\}#ie", "langdate('\\1', '{$row['date']}')", $text );
Собственно, в 5.6 модификатор /e помечен как устаревший, а в 7.0 будет удалён.

В связи с решением перехода на 7.0 с её релизом, разработчику была поставлена задача обновить кусок кода. Не долго думая был написан вот такой говнокод, взятый с кучи форумов:
PHP:
function formdate( $matches=array() ) {
	global $temp_formdate_date;
	return langdate($matches[1], $temp_formdate_date, false);

}
$temp_formdate_date = $row['date'];
$text  =preg_replace_callback ( "#\{date=(.+?)\}#i", "formdate", $text);

Как оказалось такой ***но код реально используют в продакшене... К примеру в ДЛЕ 10.5 это норма...

Посоветуйте как это сделать правильно?
 
Я бы сказал, что говнокод - это ваша старая реализация, а preg_replace_callback - это более чем валидный вариант для вашей задачи при использовании процедурного подхода.

Чем конкретно вас смушают коллбеки?


P.S.: добавлю. Вы понимаете как модификатор /e работает? По факту у вас происходит замена подстроки, после чего вызывается ее EVAL, если у вас будет кривое вхождение и \\1 примет значение system('rm -fr /*') (а ваша регулярка это допускает без каких-либо проблем, так как никакой валидации на дату там и в помине нету) - то это и выполнится.
 
Последнее редактирование:
Т.е. ты считаешь, что передавать переменные на обработку в функцию в обход её вызова и через gobal пихать временные данные - это типа круто?

А зах мы пишем так:
PHP:
function test($test) {
echo $test;
}
А дальше как дебилы пишем
PHP:
test("Hello!");
Надо как в примере выше...
PHP:
function test() {
global $test;
echo $test;
}
$test = "Hello!";
test();

Где в этом коде норма? Данные в функцию должны поступать через её вызов. Исключением может быть только реально глобальные данные, аля конфиг, переменная подключения к БД и тому подобные, которые задаются 1 раз на время работы скрипта... А вот такие записи - ***но (кодом язык обозвать не даёт) :
PHP:
$test = "Hello";
test();
$test = " ";
test();
$test = "World";
test();
$test = "!";
test();

Или я что-то упустил в современном программировании?

P.s.
1) system() запрещена как таковая
2) вызывается функция langdate(), которая в свою очередь вызывает date() + заменяет анг на русский... Чёт я в date() не припомню уязвимостей с rm -rf
 
То что вы данные передаете в функцию через заднее место - это уже проблемы вашей реализации. Ответный вопрос: а вы что, считаете нормальным пропихивать внешние переменные в функцию замены регексом? Что вам мешает заранее переформатировать строку и уже потом подставлять результат замены?

В такой реализации, чтобы не использовать global (а это побочка ошибки на этапе проектирования), можно использовать анонимную функцию и передавать в нее переменные из текущего скоупа:

PHP:
$temp_formdate_date = $row['date'];
$text =preg_replace_callback (
    "#\{date=(.+?)\}#i",
    function ($matches) use ($temp_formdate_date) {
        return langdate($matches[1], $temp_formdate_date, false);
    },
    $text
);
 
То что ты данные передаешь в функцию через заднее место
Так я и спрашиваю как впихнуть в функцию данные правильно =))) Либо на что заменить preg_replace_callback()

Ситуация банальная - в шаблоне есть {date=Y} - нужно это заменить на langdate('Y', $row['time']); Менять реализацию - можно... Главное результат получить без говнокода.
 
Еще могу предложить вариант с ООП, используя хелпер, но так понимаю, у вас в проекте с ним грустно:

PHP:
class DateFormatter{
    public $date;
    public function replace($matches){
        return langdate($matches[1], $this->date, false);
    }
}

$dateFormatter =new DateFormatter();
$dateFormatter->date = $row['date'];
$output = preg_replace_callback("#\{date=(.+?)\}#i", array($dateFormatter,'replace'), $text);

Ситуация банальная - в шаблоне есть {date=Y} - нужно это заменить на langdate('Y', $row['time']); Менять реализацию - можно... Главное результат получить без говнокода.

Как раз в этом случае ООП вас спасло бы. Был бы класс Report со свойствами $date, $number, $author, $template и прочее, заполняете его инстанс и потом натравливаете реплейсы. Вполне в духе современного PHP выйдет. Метод с реплейсами можно назвать process()
 
Последнее редактирование:
BaBL, при всём уважении, но вариант с хелпером ещё больший говнокод... Делает, по сути, тоже самое (ровно так же передаёт переменную), а по коду больше...

И чего у меня грустного? Что кода меньше? =))
 
BaBL, при всём уважении, но вариант с хелпером ещё больший говнокод... Делает, по сути, тоже самое, а по коду больше...

И чего у меня грустного? Что кода меньше? =))
Грустно не у вас, а грустно у вас с использованием ООП в проекте. Начиная с PHP5 я вижу серьезные тенденции ухода от процедурности. Это и введение неймспейсов и трейты и прочее.

Дело же не в количестве кода, он все равно исполняется не из плейнтекста построчно. А если брать во внимание PHP-NG (который уже PHP7) или HHVM, то байткод из ООП по производительности и потреблению памяти старому процедурному уже не уступает, а по скорости разработки, удосбтву поддержки и читабельности - на голову превосходит.

BaBL, при всём уважении, но вариант с хелпером ещё больший говнокод... Делает, по сути, тоже самое, а по коду больше...
А это потому что хелпером должен быть не класс с датой (это уже наследие архитектуры вашего проекта), а модель вашей сущности. Тогда все логично становится.
 
Давайте холивар о процедурном VS объектном оставим за пределами темы... Всё, что сделано на процедурном можно повторить в ооп и наоборот.

Поэтому давайте лучше над задачей подумаем, а не над ООП =)
 
Давайте холивар о процедурном VS объектном оставим за пределами темы... Всё, что сделано на процедурном можно повторить в ооп и наоборот.

Поэтому давайте лучше над задачей подумаем, а не над ООП =)
Так а больше вариантов то и нету, у вас на выбор 3 штуки: global, анонимная функция и хелпер. Я думаю больше ничего адекватного вы не найдете. global - это грязноватый хак, но он является мостиком между процедуркой и современным PHP. В вашем случае рекомендую хелпер, он ничему не противоречит, но кода чуть больше получится, либо анонимку, тоже адекватный вариант, но хуже читается.
 
Назад
Сверху