...

пятница, 18 апреля 2014 г.

PHP-расширение dom_varimport: быстрое преобразования вложенных массивов в DOMDocument

Некоторые проекты используют XSLT в качестве основного «движка» шаблонов. Помимо известных недостатков XSLT (например, его многословности, относительной медлительности и т.д.) у него есть и преимущества: «стандартность» языка, его идеология отсутствия «побочных эффектов» и pattern matching, возможность при необходимости вызывать методы helper-классов из шаблонов (через exslt-расширение). Какое-то время назад я выкладывал библиотеку ShortXSLT, позволяющую вместо громоздких и ... писать просто {/root/abc} и {if...}...{elseif}...{/if} без потери производительности, так что проблема многословности отчасти решается.

Но сейчас речь не о преимуществах и недостатках XSLT (я уверен, и противники, и сторонники этой технологии найдутся в изобилии). Я бы хотел описать один прием, который удобно применять в существующих проектах с XSLT-шаблонами, и привести ссылку на библиотеку, реализующую данный прием с хорошей производительностью.


Передаем данные в XSLT, минуя генерацию текстового представления XML



Представьте, что у нас есть контроллер, генерирующий некоторый вложенный PHP-список объектов для отображения на странице. Он должен этот массив преобразовать в XML, который потом пойдет на вход XSLT-шаблону. Хорошо бы, чтобы данное преобразование из структур PHP в XML выполнялось не вручную в каждом контроллере, а был некоторый промежуточный слой абстракции, который умеет применять XSLT-шаблон прямо к PHP-данным, минуя текстовое XML-представление. Так мы уменьшим вероятность ошибок, да и письмо сократится. Мы сможем работать с XSLT-шаблонами напрямую, минуя XML-представление данных.

Некоторое время назад я написал на Си PHP-расширение dom_varimport (также выложено на GitHub). Оно содержит одноименную функцию, на вход которой подается объект DOMDocument и PHP-массив любой вложенности. Функция заполняет переданный ей DOMDocument XML-представлением входного массива, и делает она это очень быстро — примерно в 20 раз быстрее, чем делал бы код, написанный на чистом PHP. Большой документ размером около 1 МБ с тысячами вложенных свойств и объектов формируется примерно за 1-2 миллисекунды.


Например, вызов:



$doc = new DOMDocument();
dom_varimport(
$doc,
array(
"some_key" => 111,
123,
0.5,
"arr" => array("1a" => "1a"),
"obj" => (object)array("prop" => "val"),
true,
false,
"b" => null,
"empty" => array(),
),
"root" // optional, defaults to "root"
);
$doc->formatOutput = true;
echo $doc->saveXML(); // это только для отладки: на практике вам не нужно будет вызывать saveXML()



напечатает вот такой XML-документ:

<?xml version="1.0"?>
<root>
<some_key key="some_key">111</some_key> <!-- plain key=value -->
<item key="0">123</item> <!-- numeric keys are "item" tags -->
<item key="1">0.5</item> <!-- double -->
<arr key="arr"> <!-- nested array -->
<item key="1a">1a</item> <!-- invalid tag names are converted to "item" -->
</arr>
<obj key="obj"> <!-- nested object -->
<prop key="prop">val</prop>
</obj>
<item key="2">1</item> <!-- true converts to 1 -->
<item key="3"/> <!-- false converts to an empty string -->
<b key="b"/> <!-- null also converts to an empty string -->
<empty key="empty"/> <!-- empty array is an empty element -->
</root>



Все достаточно прозрачно: ключи массива и свойства объектов становятся XML-элементами, по возможности с теми же именами (но если имя недопустимо для XML-элемента, то вместо него используется «item»). Такой XML-документ очень легко читать при отладке, он весьма компактен. Итак, мы получаем на выходе объект DOMDocument, который уже можем передать XSLTProcessor-у. Текстовое представление XML нигде не фигурирует, нигде не парсится.
Как установить расширение



Расширение написано на Си, поэтому его нужно откомпилировать на машине, на которой установлены GCC и пакеты типа php5-src (или php5-devel). Это совсем не страшно:

git clone http://ift.tt/1hSnXnd
cd dom_varimport
phpize
./configure
make
make test
make install # or copy modules/dom_varimport.so manually
phpize --clean



Этап «make install» можно и не делать: достаточно взять бинарный файл modules/dom_varimport.so и скопировать его в директорию с расширениями PHP (например, /usr/lib/php5), в том числе и на других машинах. Наконец, нужно в подключить расширение /etc/php5/conf.d/dom_varimport.ini и перезапустить php5-fpm или apache:

extension = /usr/lib/php5/dom_varimport.so

This entry passed through the Full-Text RSS service — if this is your content and you're reading it on someone else's site, please read the FAQ at http://ift.tt/jcXqJW.


Комментариев нет:

Отправить комментарий