Может ли кто-нибудь сказать мне, компилирует ли PHP выражения XPath и когда? Было бы полезно знать как классы simpleXML, так и DOMDocument. Я также хочу знать, где хранится скомпилированный XPath.






Все функции PHP XML построены на основе библиотека libxml2, поэтому часть ответа будет зависеть от того, как эта библиотека работает, а часть - от того, как именно PHP ее использует.
Начиная с SimpleXML, мы можем найти реализацию SimpleXMLElement->xpath() в ext / simplexml / simplexml.c. Пропустив некоторые внутренние операции, проверку типов параметров и т. д., Первая интересная строка, которую мы находим, такова:
if (!sxe->xpath) {
sxe->xpath = xmlXPathNewContext((xmlDocPtr) sxe->document->ptr);
}
Таким образом, повторяющиеся выражения XPath на одном и том же SimpleXMLElement будут использовать один и тот же «контекст XPath», но не будут использоваться другими экземплярами. Далее мы находим, где это используется:
retval = xmlXPathEval((xmlChar *)query, sxe->xpath);
Итак, PHP вызывает функцию libxml xmlXPathEval, которая просто берет строку и контекст и немедленно их оценивает. Руководство по libxml для xmlXPathEval` говорит:
Evaluate the XPath Location Path in the given context.
Returns: the xmlXPathObjectPtr resulting from the evaluation or NULL. the caller has to free the object.
И действительно, PHP освобождает этот результат в конце метода:
xmlXPathFreeObject(retval);
Итак, по крайней мере, в SimpleXML нет отдельного шага компиляции, и между вызовами метода ничего не сохраняется.
Версия DOM немного сложнее, потому что в ней есть видимый пользователю объект, представляющий контекст XPath, который определен в /ext/dom/xpath.c. Во-первых, как и следовало ожидать, конструктор устанавливает контекст:
PHP_METHOD(domxpath, __construct)
{
# ...
ctx = xmlXPathNewContext(docp);
Затем он творит чудеса, чтобы повторно использовать этот контекст, где это возможно, но мы еще не скомпилировали XPath, это просто контекст, то есть «текущий узел», с которым нужно сравнивать выражения. В определениях как для ->eval(), так и для ->query() используется одна и та же реализация C, php_xpath_eval. Это проверяет правильность некоторого внутреннего состояния, а затем вызывает:
xpathobjp = xmlXPathEvalExpression((xmlChar *) expr, ctxp);
Это другая функция, поэтому мы можем поищи это в libxml:
Function: xmlXPathEvalExpression Alias for xmlXPathEval().
Так что, оказывается, разницы все-таки нет. Опять же, он передал строку, возвращает результат, и функция PHP освобождает этот результат перед возвратом:
xmlXPathFreeObject(xpathobjp);
Итак, как и раньше: нет явной компиляции, и единственное, что хранится между вызовами, - это «контекст», с которым будут выполняться выражения XPath.
Получается libxml поддерживает какой-то кеш, если включить через xmlXPathContextSetCache:
Creates/frees an object cache on the XPath context. If activates XPath objects (xmlXPathObject) will be cached internally to be reused. @options: 0: This will set the XPath object caching: @value: This will set the maximum number of XPath objects to be cached per slot There are 5 slots for: node-set, string, number, boolean, and misc objects. Use <0 for the default number (100). Other values for @options have currently no effect.
В случае SimpleXML этот кеш в любом случае бесполезен, поскольку контекст отбрасывается после использования; для DOM это было бы более уместно, поскольку контекст - и, следовательно, кеш - будет существовать до тех пор, пока объект PHP DOMXPath.
Мы можем покопаться в реализации xmlXpathNewContext, чтобы увидеть, включен или отключен этот кеш по умолчанию:
#ifdef XP_DEFAULT_CACHE_ON
if (xmlXPathContextSetCache(ret, 1, -1, 0) == -1) {
xmlXPathFreeContext(ret);
return(NULL);
}
#endif
Получается, что это параметр времени компиляции - если для libxml, скомпилированного или загруженного в ваш PHP, этот флаг был установлен при компиляции, я полагаю, что в случае DOM XPath вы будете иметь некоторую степень кэширования, в одном экземпляре DOMXPath`.
Хм, это очень обидно. Спасибо, это отличная детективная работа.
@Kaan Меня настораживало, что я просто предположил что-то, поэтому я сделал еще один шаг и добавил, может быть, несколько лучших новостей.
Хорошо, так как вы отредактировали свой ответ, это немного менее разочаровывает. Тем не менее, разочарование. Я надеялся, что какой-то скомпилированный код выдержит несколько исполнений. Теперь мне, вероятно, придется изменить свой код, чтобы просто использовать кеш за одно выполнение.
Я не знаю ответа, но полагаю, что это будет «то, что делает libxml2», поскольку на этом построены все XML-функциональные возможности PHP. Таким образом, домашняя страница libxml, вероятно, является хорошей отправной точкой для исследования.