preg_replace() /e

Тема в разделе "PHP", создана пользователем Горбушка, 22 июн 2015.

Модераторы: latteo
  1. Горбушка

    Горбушка Ищу её...

    Регистр.:
    2 май 2008
    Сообщения:
    3.035
    Симпатии:
    2.034
    Есть вот такой код... Он заменяет всякие {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_datefalse);

    }
    $temp_formdate_date $row['date'];
    $text  =preg_replace_callback "#\{date=(.+?)\}#i""formdate"$text);
    Как оказалось такой ***но код реально используют в продакшене... К примеру в ДЛЕ 10.5 это норма...

    Посоветуйте как это сделать правильно?
     
  2. BaBL

    BaBL Постоялец

    Регистр.:
    13 ноя 2012
    Сообщения:
    144
    Симпатии:
    87
    Я бы сказал, что говнокод - это ваша старая реализация, а preg_replace_callback - это более чем валидный вариант для вашей задачи при использовании процедурного подхода.

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


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

    Горбушка Ищу её...

    Регистр.:
    2 май 2008
    Сообщения:
    3.035
    Симпатии:
    2.034
    Т.е. ты считаешь, что передавать переменные на обработку в функцию в обход её вызова и через 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
     
  4. BaBL

    BaBL Постоялец

    Регистр.:
    13 ноя 2012
    Сообщения:
    144
    Симпатии:
    87
    То что вы данные передаете в функцию через заднее место - это уже проблемы вашей реализации. Ответный вопрос: а вы что, считаете нормальным пропихивать внешние переменные в функцию замены регексом? Что вам мешает заранее переформатировать строку и уже потом подставлять результат замены?

    В такой реализации, чтобы не использовать 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_datefalse);
        },
        
    $text
    );
     
  5. Горбушка

    Горбушка Ищу её...

    Регистр.:
    2 май 2008
    Сообщения:
    3.035
    Симпатии:
    2.034
    Так я и спрашиваю как впихнуть в функцию данные правильно =))) Либо на что заменить preg_replace_callback()

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

    BaBL Постоялец

    Регистр.:
    13 ноя 2012
    Сообщения:
    144
    Симпатии:
    87
    Еще могу предложить вариант с ООП, используя хелпер, но так понимаю, у вас в проекте с ним грустно:

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

    $dateFormatter =new DateFormatter();
    $dateFormatter->date $row['date'];
    $output preg_replace_callback("#\{date=(.+?)\}#i", array($dateFormatter,'replace'), $text);
    Как раз в этом случае ООП вас спасло бы. Был бы класс Report со свойствами $date, $number, $author, $template и прочее, заполняете его инстанс и потом натравливаете реплейсы. Вполне в духе современного PHP выйдет. Метод с реплейсами можно назвать process()
     
    Последнее редактирование: 22 июн 2015
    venetu нравится это.
  7. Горбушка

    Горбушка Ищу её...

    Регистр.:
    2 май 2008
    Сообщения:
    3.035
    Симпатии:
    2.034
    BaBL, при всём уважении, но вариант с хелпером ещё больший говнокод... Делает, по сути, тоже самое (ровно так же передаёт переменную), а по коду больше...

    И чего у меня грустного? Что кода меньше? =))
     
  8. BaBL

    BaBL Постоялец

    Регистр.:
    13 ноя 2012
    Сообщения:
    144
    Симпатии:
    87
    Грустно не у вас, а грустно у вас с использованием ООП в проекте. Начиная с PHP5 я вижу серьезные тенденции ухода от процедурности. Это и введение неймспейсов и трейты и прочее.

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

    А это потому что хелпером должен быть не класс с датой (это уже наследие архитектуры вашего проекта), а модель вашей сущности. Тогда все логично становится.
     
  9. Горбушка

    Горбушка Ищу её...

    Регистр.:
    2 май 2008
    Сообщения:
    3.035
    Симпатии:
    2.034
    Давайте холивар о процедурном VS объектном оставим за пределами темы... Всё, что сделано на процедурном можно повторить в ооп и наоборот.

    Поэтому давайте лучше над задачей подумаем, а не над ООП =)
     
  10. BaBL

    BaBL Постоялец

    Регистр.:
    13 ноя 2012
    Сообщения:
    144
    Симпатии:
    87
    Так а больше вариантов то и нету, у вас на выбор 3 штуки: global, анонимная функция и хелпер. Я думаю больше ничего адекватного вы не найдете. global - это грязноватый хак, но он является мостиком между процедуркой и современным PHP. В вашем случае рекомендую хелпер, он ничему не противоречит, но кода чуть больше получится, либо анонимку, тоже адекватный вариант, но хуже читается.
     
    Горбушка нравится это.