myEngine

English

Описание.
myEngine - это пример использования технологий XML/XSLT в связке с PHP. Чтобы лучше понять что такое myEngine я сделаю небольшое отступление. Итак...

Даю мышку на отсечение :~) работать с PHP вы начинали приблизительно так:
<html>
  <head>
    <title><?php print $page_title; ?></title>
  </head>
  <body><?php showBodyContent(); ?></body>
</html>
т.е. вставляли PHP код непосредственно в HTML разметку. А чем плохо? Так начинался PHP. Затем, возможно, вы начали использовать Template Engines или даже писать свой собственный. Всё это понадобилось тогда, когда проекты разраслись, когда для работы над проектом обьединялись несколько человек, когда началось разделение труда дизайнера и програмиста. Тогда начали проявляться недостатки вышеуказанного подхода: сильная связь дизайна и програмного кода; последовательная обработка документа. Эти и некоторые другие недостатки попробовали исправить с помощью Template Engines. При этом приходиться изучать используемый синтаксис и работу таких движков.

Но вот появилась технология XML/XSLT которая не имеет этих недостатков по определению. Как применить её для своих нужд?
Для начала, хочу обратить ваше внимание на некоторые обстоятельства. Что вам напоминает вышеприведенный пример кода?.. XML документ! А на что похожи вставки PHP кода?.. На processing-instruction. Итак, мы можем использовать привычный нам подход. Ведь XML документ не содержит дизайн, а последовательность обработки нам не важна. Как и раньше, PHP процессор пробежится по файлу, выполнит свой код и отдаст всё в браузер.
А если браузер не умеет обрабатывать XML документ? Тогда можно перехватить вывод страницы (например исплоьзуя буферизацию вывода) и отдать XSLT процессору. В большинстве случаев такого подхода достаточно.

Но. Как всегда появляется какое-то "Но". PHP процессор воспринимает содержимое как строку. Как раньше так и сейчас, чтобы ни делал ваш PHP код, он должен выдать строку которая будет отправлена в браузер. А всё что было выведено до вашего кода в начале страницы - коду не известно. Такой функциональности может оказаться недостаточно. Вот если бы PHP парсил XML документ в Document Object Model и предоставлял интерфейс к этому документу.

Представьте что у вас есть такой PHP. Тогда вы пишите обыкновенный XML документ и вставляете, где необходимо, PHP код. Но теперь ваш код может возвращать не только строку но и объекты - потомки объекта Node. Если возвращается строка, она добавляется в DOM документ как текстовый узел. Если возвращается объект - потомок объекта Node, он импортируется в DOM документ и включается в дерево. Затем DOM документ отдаётся XSLT процессору.

Именно такой подход позволяет реализовать библиотека myXML (a с выходом PHP5 он будет возможен и без этой библиотеки). А класс myEngine - это пример реализации данного подхода.

Конечно есть и ограничения. PHP processing-instruction не могут быть вставлены в значения атрибутов. Поэтому в myXML включена поддержка переменных и констант в значениях атрибутов, а также выполнение php кода. Например:
<?xml version="1.0">
<?xml-stylesheet href="style.xsl" type="text/xsl">
<page title="<?php return PAGE_TITLE; ?>">
  <!-- Так делать нельзя. Используйте -->
  <page title="{$page_title}">
  <!-- или -->
  <page title="{PAGE_TITLE}">
  <!-- или -->
  <page title="php: return $page_title;">
</page>
В первом случае должна существовать глобальная переменная $page_title значение которой и будет использовано в качестве атрибута. Во втором случае должна существовать константа PAGE_TITLE. В противном случае значением атрибута будет имя константы.
Следующее ограничение - это видимость переменных. PHP код выполняется в окружении метода myXML::processingInstructionHandler(). При обработке PHP processing-instruction в этом методе выполняется простой код:
function processingInstructionHandler($parser, $target, $data)
{
    ...code...
    
    $keys = array_keys($GLOBALS);
    foreach ($keys as $key) {
        $$key =& $GLOBALS[$key];
    }
    
    ...code...
}
который создаёт локальные переменные - указатели на глобальные переменные с таким же именем (вы можете спросить почему не используется функция extract() - потому что она создаёт копии глобальных переменных, и только начиная с версии PHP 4.3 она умеет делать указатели). В результате, PHP processing-instruction выполняются как бы в едином глобальном окружении. Но если вы объявите переменную внутри PHP processing-instruction она будет принадлежать окружению метода myXML::processingInstructionHandler(). Для того чтобы она стала глобальной воспользуйтесь массивом $GLOBALS или инструкцией global. Например:
<?xml version="1.0">
<?xml-stylesheet href="style.xsl" type="text/xsl">
<?php $GLOBALS['simple_var'] = 'Simple String'; ?>
<!-- или -->
<?php
  global $simple_var;
  $simple_var = 'Simple String';
?>
<?php
  //Здесь уже не нужно объявлять глобальную переменную.
  return $simple_var;
?>
</page>
И наконец, в одном элементе processing-instruction можно вывести только одно значение строки или объекта.

Минимальные объяснения по работе функций приведены непосредственно в коде. Подробные объяснения будут по мере востребования. По всем вопросам пишите на

Ссылки.
Изменения.
Загрузка.

По всем вопросам пишите на