Как и многие другие, я предпочитаю использовать процедурный PHP в качестве языка шаблонов . Хотя синтаксис PHP делает его практичным выбором, существует проблема с встраиванием динамического контента. Большинство PHP-приложений генерируют HTML-вывод, поэтому вы в конечном итоге много пишете <?php echo htmlspecialchars($foo);?>
, Используя эту технику. Или вы забудете об этом и сделаете ваше приложение подверженным всевозможным неприятным атакам XSS
Помимо раздражения от лишней типизации, есть опасность стать ленивым, увидев, что <?php echo $foo;?>
Заметно короче типа. В некоторых ситуациях это также не проявляется как проблема, поскольку некоторые типы содержимого никогда не содержат специальных символов HTML (например, Numbers). Это особенно неприятно, потому что ошибки в слое представления общеизвестно трудно отследить, и в отличие от SQL-инъекций — похожая проблема — последствия, как правило, наносят ущерб пользователям сайта, а не непосредственно сайту.
ПОЦЕЛУЙ
Недавно я посмотрел код, написанный для CakePHP . Мой взгляд поймал функцию e
, которая является сокращением для echo
. Обычная функция, состоящая из одной буквы, несомненно, является самым простым способом расширения синтаксиса PHP. Думая об этом, это довольно очевидно, но мне это никогда не приходило в голову.
Что ж, разработчики CakePHP допустили ошибку, так как это должно было быть сокращением для echo htmlspecialchars
. Тем не менее, синтаксис работает хорошо. Поэтому я начал использовать глобально определенную функцию, которая выглядит примерно так:
function e($string) { echo htmlspecialchars($string); }
function e($string) { echo htmlspecialchars($string); }
И это тоже работает. Это избавляет меня от необходимости печатать и не забывает выходить из выходных данных, потому что мне нужно больше работать, чтобы выводить строки без экранирования, чем нет. Простой, но мощный.
Столкновение
Есть проблема, хотя; Поскольку это такое хорошее название для функции, есть вероятность, что кто-то другой будет использовать ее для чего-то другого или, возможно, даже для того же самого. Я уже знаю по крайней мере один потенциальный конфликт имен, так как я получил идею от CakePHP.
Обычный способ справиться с этим — использовать пространства имен, но, увы, PHP не имеет пространств имен ( пока ), и общее решение псевдо-пространств имен (например, имен с префиксами) здесь не работает, так как оно не поддается Цель функции в первую очередь.
Есть и другая проблема. В тех немногих случаях, когда мы не визуализируем вывод HTML / XML, мы не хотим экранировать строки для встраивания в HTML / XML — вместо этого мы хотим экранировать их для встраивания в этот целевой язык. Даже в HTML может потребоваться экранирование строк с htmlentities , а не htmlspecialchars , если кодировка текста не соответствует ISO-8859-1. Или закодируйте строку в UTF-8, если шаблон находится в UTF-8.
Создание статической динамики
Проблема всего этого в том, что функция является статической — такова природа глобальных функций в PHP. Другие интерпретируемые языки позволяют нам переопределять функции во время выполнения, но с PHP не повезло (ну, строго говоря, runkit это позволяет, но никто в здравом уме не будет использовать его в производственной среде).
Однако есть лазейка; Используя обратный вызов , мы можем делегировать динамически определенный обработчик:
if (!function_exists('e')) { function e($args) { $args = func_get_args(); return call_user_func_array($GLOBALS['_global_function_handler_e'], $args); } }
if (!function_exists('e')) { function e($args) { $args = func_get_args(); return call_user_func_array($GLOBALS['_global_function_handler_e'], $args); } }
Намного лучше — теперь я могу определить свой собственный обработчик вывода как:
$GLOBALS['_global_function_handler_e'] = 'my_global_function_handler_e'; function my_global_function_handler_e($string) { echo htmlspecialchars($string); }
$GLOBALS['_global_function_handler_e'] = 'my_global_function_handler_e'; function my_global_function_handler_e($string) { echo htmlspecialchars($string); }
И CakePHP может использовать:
$GLOBALS['_global_function_handler_e'] = 'cakephp_global_function_handler_e'; function cakephp_global_function_handler_e($string) { echo htmlspecialchars($string); }
$GLOBALS['_global_function_handler_e'] = 'cakephp_global_function_handler_e'; function cakephp_global_function_handler_e($string) { echo htmlspecialchars($string); }
Мы все еще используем глобальный символ, но, по крайней мере, он динамический, а не статический.
Итак, вот призыв к создателям фреймворков в мире PHP: если бы мы все согласились сделать это для любой функции, определенной в глобальной области видимости, которая имеет очевидный риск столкновения имен , я думаю, что нам всем было бы лучше.
Просто скромное предложение, конечно.