PHP编译XPath

时间:2018-05-22 04:17:13

标签: php xpath simplexml domdocument

有人能告诉我PHP是否以及何时编译XPath表达式?知道simpleXML和DOMDocument类会很有用。我还想知道编译的XPath的存储位置。

1 个答案:

答案 0 :(得分:1)

PHP的XML功能都建立在the libxml2 library之上,因此部分答案将取决于该库的工作方式,以及PHP如何使用它。

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

if (!sxe->xpath) {
    sxe->xpath = xmlXPathNewContext((xmlDocPtr) sxe->document->ptr);
}

因此,在同一SimpleXMLElement上重复的XPath表达式将使用相同的" XPath上下文",但它不会与其他实例共享。再往下,我们找到了使用它的地方:

retval = xmlXPathEval((xmlChar *)query, sxe->xpath);

因此PHP调用了一个libxml函数xmlXPathEval,它只接受一个字符串和一个上下文,并立即对其进行求值。 libxml manual for xmlXPathEval`说:

  

在给定的上下文中评估XPath位置路径。

     

返回:评估产生的xmlXPathObjectPtr或NULL。调用者必须释放该对象。

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

xmlXPathFreeObject(retval);

因此,至少在SimpleXML中,没有单独的编译步骤,并且在对方法的调用之间不存储任何内容。

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

PHP_METHOD(domxpath, __construct)
{
    # ...
    ctx = xmlXPathNewContext(docp);

然后尽可能重用这个上下文,但是我们还没有编译任何 XPath ,这只是 context ,即& #34;当前节点"比较表达式。 ->eval()->query()的定义使用相同的C实现php_xpath_eval。这检查一些内部状态是否正确,然后调用:

xpathobjp = xmlXPathEvalExpression((xmlChar *) expr, ctxp);

这是一个不同的功能,所以我们可以look it up in libxml

  

功能:xmlXPathEvalExpression   xmlXPathEval()的别名。

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

xmlXPathFreeObject(xpathobjp);

所以,和以前一样:没有明确的编译,并且在调用之间存储的唯一内容是" context"用于运行XPath表达式。

事实证明,如果通过xmlXPathContextSetCache启用了libxml 支持某种缓存:

  

在XPath上下文中创建/释放对象缓存。如果激活XPath对象(xmlXPathObject)将在内部缓存以供重用。 @options:0:这将设置XPath对象缓存:@value:这将设置每个槽缓存的最大XPath对象数有5个槽:node-set,string,number,boolean和misc对象。使用< 0表示默认数字(100)。 @options的其他值目前没有效果。

对于SimpleXML,此缓存无论如何都不会有用,因为上下文在使用后被丢弃;对于DOM,它会更相关,因为上下文 - 因此缓存 - 只要与PHP DOMXPath对象一样长。

我们可以dig into the implementation of xmlXpathNewContext查看默认情况下是启用还是禁用此缓存:

#ifdef XP_DEFAULT_CACHE_ON
    if (xmlXPathContextSetCache(ret, 1, -1, 0) == -1) {
    xmlXPathFreeContext(ret);
    return(NULL);
    }
#endif

所以事实证明这是编译时选项 - 如果编译或加载到PHP中的libxml在编译时设置了这个标志,我相信你会,在DOM XPath的情况下,在单个DOMXPath`实例中有一定程度的缓存,