PHP编译XPath吗

PHP编译XPath吗,php,xpath,simplexml,domdocument,Php,Xpath,Simplexml,Domdocument,谁能告诉我PHP是否以及何时编译XPath表达式?了解simpleXML和DOMDocument类都很有用。我还想知道编译后的XPath存储在哪里 PHP的XML功能都是建立在上面的,因此部分答案将取决于该库的工作方式,部分取决于PHP如何准确地使用它 从SimpleXML开始,我们可以在中找到simplexmlement->xpath()的实现。跳过一些内部管理、检查参数类型等,我们发现的第一行有趣的内容是: if (!sxe->xpath) { sxe->xpath =

谁能告诉我PHP是否以及何时编译XPath表达式?了解simpleXML和DOMDocument类都很有用。我还想知道编译后的XPath存储在哪里

PHP的XML功能都是建立在上面的,因此部分答案将取决于该库的工作方式,部分取决于PHP如何准确地使用它

从SimpleXML开始,我们可以在中找到
simplexmlement->xpath()
的实现。跳过一些内部管理、检查参数类型等,我们发现的第一行有趣的内容是:

if (!sxe->xpath) {
    sxe->xpath = xmlXPathNewContext((xmlDocPtr) sxe->document->ptr);
}
因此,在同一个
simplexmlement
上重复的XPath表达式将使用相同的“XPath上下文”,但不会与其他实例共享。再往下看,我们会发现这是在哪里使用的:

retval = xmlXPathEval((xmlChar *)query, sxe->xpath);
因此,PHP正在调用一个libxml函数
xmlXPathEval
,该函数只接受一个字符串和一个上下文,并立即对其求值。报告说:

在给定上下文中计算XPath位置路径

返回:求值产生的xmlXPathObjectPtr或NULL。调用方必须释放对象

事实上,PHP会在方法结束时释放该结果:

xmlXPathFreeObject(retval);
因此,至少在SimpleXML中,没有单独的编译步骤,并且在方法调用之间没有存储任何内容

DOM版本有点复杂,因为它有一个表示XPath上下文的用户可见对象,该对象在中定义。首先,构造函数设置上下文,正如您所期望的:

PHP_METHOD(domxpath, __construct)
{
    # ...
    ctx = xmlXPathNewContext(docp);
然后,在可能的情况下重用这个上下文会有一些魔力,但我们还没有编译任何XPath,这只是上下文,即用于比较表达式的“当前节点”。
->eval()
->query()
的定义都使用相同的C实现,
php\u xpath\u eval
。这将检查某些内部状态是否正确,然后调用:

xpathobjp = xmlXPathEvalExpression((xmlChar *) expr, ctxp);
这是一个不同的函数,因此我们可以:

函数:xmlXPathEvalExpression xmlXPathEval()的别名

所以,事实证明这根本没有区别。同样,它传递一个字符串,返回一个结果,PHP函数在返回之前释放该结果:

xmlXPathFreeObject(xpathobjp);
因此,和以前一样:没有显式编译,调用之间存储的唯一内容是XPath表达式要运行的“上下文”

事实证明,如果通过以下方式启用,libxml确实支持某种缓存:


在XPath上下文上创建/释放对象缓存。如果激活,XPath对象(xmlXPathObject)将在内部缓存以重用@选项:0:这将设置XPath对象缓存:@value:这将设置每个插槽要缓存的XPath对象的最大数量有5个插槽:节点集、字符串、数字、布尔值和杂项对象。使用我不知道答案,但我想它将是“无论libxml2做什么”,因为所有PHP的XML功能都是建立在这个基础上的。因此,这可能是一个很好的研究起点。嗯,这非常令人失望。不过,谢谢,这是一项很棒的侦探工作。@Kaan这让我感到不安,因为我刚刚假设了一些东西,所以我进一步挖掘,并添加了一些可能稍微好一点的消息。好吧,既然你编辑了你的答案,这就稍微不那么令人失望了。但仍然令人失望。我希望一些编译后的代码能够跨越多次执行。现在,我可能不得不简单地修改代码,以便在一次执行中使用缓存。
#ifdef XP_DEFAULT_CACHE_ON
    if (xmlXPathContextSetCache(ret, 1, -1, 0) == -1) {
    xmlXPathFreeContext(ret);
    return(NULL);
    }
#endif