Кстати, только сейчас заметил… Вот мы выполняем наши чанки и сниппеты через Smarty-теги, и радуемся тому, что в кеше страницы уже конечный HTML. НО, как оказалось, выполняемые сниппеты и чанки со всем своим хламом все равно попадают в кеш страницы, просто в другие элементы кеш-массива. Итог: полезный HTML страницы — 700 строк (на своем примере беру), а плюс к нему еще 4000 строк всякого хлама. Вот спрашивается «и нафига оно там мне надо». Особо обращаю внимание на то, что это индивидуальный кеш каждой страницы в отдельности, а не какой-то общий кеш. То есть на 100 страниц на весь их полезный HTML в кеше, я буду иметь еще в 6 раз больше кеша всякого хлама.
В чем тут соль? Дело в том, что конечный контент на вывод — это кеш-элементе _content. Но есть еще элемент sourceCache. Вот в него и набиваются все наши чанки, сниппеты и т.п. Меня все это еще больше удивляет в том плане, что тот же код сниппетов совершенно бессмысленный там (лично на мой взгляд). Ведь сниппеты не выполняются через EVAL (как это было в MODX Evolution), теперь сниппеты на выходе — это функции, находящиеся в отдельных файлах. Так вот, если это функция в отдельном файле, нафига мне ее код в кеше страницы? Ведь бывают очень даже не маленькие сниппеты (далее в статье я это докажу).
Так как же они туда попадают? Логично было копать через метод modX::runProcessor(). А он меня привел к нашему любимому MODX-парсеру, в частности к методу modParser::getElement(). Смотрим:
public function getElement($class, $name) {
$realname = $this->realname($name);
if (array_key_exists($class, $this->modx->sourceCache) && array_key_exists($realname, $this->modx->sourceCache[$class])) {
/** @var modElement $element */
$element = $this->modx->newObject($class);
$element->fromArray($this->modx->sourceCache[$class][$realname]['fields'], '', true, true);
$element->setPolicies($this->modx->sourceCache[$class][$realname]['policies']);
if (!empty($this->modx->sourceCache[$class][$realname]['source'])) {
if (!empty($this->modx->sourceCache[$class][$realname]['source']['class_key'])) {
$sourceClassKey = $this->modx->sourceCache[$class][$realname]['source']['class_key'];
$this->modx->loadClass('sources.modMediaSource');
/* @var modMediaSource $source */
$source = $this->modx->newObject($sourceClassKey);
$source->fromArray($this->modx->sourceCache[$class][$realname]['source'],'',true,true);
$element->addOne($source,'Source');
}
}
} else {
/** @var modElement $element */
$element = $this->modx->getObjectGraph($class,array('Source' => array()),array('name' => $realname), true);
if ($element && array_key_exists($class, $this->modx->sourceCache)) {
$this->modx->sourceCache[$class][$realname] = array(
'fields' => $element->toArray(),
'policies' => $element->getPolicies(),
'source' => $element->Source ? $element->Source->toArray() : array(),
);
}
}
if ($element instanceof modElement) {
$element->set('name', $name);
}
return $element;
}
Вот как раз здесь мы и видим, как этот кеш устанавливается. $this->modx->sourceCache[$class][$realname] =
Конечно, здесь еще нет сохранения (кеш сохраняется уже после окончательного рендерера страницы, но именно этот элемент и попадает в общий кеш страницы).
Вот к примеру, я взял и урезал часть этого кеша:
$fields = $element->toArray();
unset($fields['snippet']);
unset($fields['content']);
$this->modx->sourceCache[$class][$realname] = array(
'fields' => $fields,
'policies' => $element->getPolicies(),
'source' => $element->Source ? $element->Source->toArray() : array(),
);
То есть я из всего массива элемента удалил его исходные коды и все. Сохранил, обновил — сайт как работал, так и работает. Потому что как я и говорил выше, те же сниппеты находятся в отдельных файлах.
Вот это уже сократило кеш-файл с 4700 строк до 2500 строк.
Но я попробовал и еще более радикальный шаг — удалил вообще все, оставив только id-шник элемента. Единственное что я заметил из того, что слетело — параметр RAND некорректно Wayfinder-ом обработался (читай запрос сломался). Но во-первых, это лечится (есть процессор-замена Wayfinder-у), а во-вторых, кеш сократился до 900 строк.
Может, конечно, я и утрирую немного, может оно особо и не влияет на производительность (хотя помимо производительности ведь еще и другие вопросы есть. К примеру общий объем кеша. В моем случае после этих мелких правок он сократился с 201Кб до 46 Кб. То есть выигрыш 150 метров на 1000 документов), но все равно, я думаю, это можно было бы сделать и более экономно. Да, я понимаю, что какие-то элементы могут несколько раз на странице быть вызваны за один раз, но можно разделить же кешируемые на некешируемые. Если не было некешируемого скрипта (если все они или он кешируемый)… Нет, пишу, и понимаю, что все запущено, что все не так… У нас рекурсии, глобальные плейсхолдеры и т.д. и т.п. Вот чесслово, все это на мой взгляд так противоречит базовым принципам php-программирования (в плане областей видимости и т.п.). Из-за этих вложенных элементов (что теги могут быть внутри других тегов, и какие-то из них могут быть не кешируемыми и т.д. и т.п.), из-за этой рекурсии на выполнение (выполненный тег может вернуть другой тег, который в свою очередь тоже будет выполнен, а не просто как текст воспринят), все это дает маленький выигрыш в простоте, но дает бешенные сложности в плане организации кеша и оптимизации в принципе. В том же Smarty нет такой рекурсии (что выполни какой-то шаблон, получи код, обработай его опять, если найдешь в полученном коде Smarty-теги и т.п.), но это никак не мешает программировать сайт. Логика — в процессорах (и там рекурсия есть, если надо), представление — отдельно (в смарти-шаблоне). Но зато полное управление кешем. А здесь…
Давным-давно меня Райн спросил «а что ты не возьмешь отдельно xPDO, Smarty и не сделаешь свой движок?». Но он сам и ответил улыбаясь «TV-параметры, ACL, гибкая админка и т.п.». Да, это то, что мне очень нравится в MODX-е. Но вот над работой фронт-энда еще работать и работать. Я еще одно исследование еще не опубликовал (более обстоятельное), я его просто еще не закончил. Но оно меня, честно сказать, совсем пока не радует результатами…
Нет, я не планирую соскакивать, я думаю, мы постоянно развиваем MODX и он будет более производительный и т.п., но все равно иногда очень не весело.
Блин, хотел исследование написать, а получился какой-то крик души… Вот так всегда получается, когда начинаешь писать топик еще на уровне зацепки (чтобы описать все, каждый шаг, чтобы ничего не забыть и не переврать), а в процессе получаешь такие результаты и такие выводы делаешь, которые вообще не ожидал…