PHP 是否编译 XPath

Does PHP compile XPath

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

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 context",但不会与其他实例共享。再往下,我们找到这个用在什么地方:

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

所以 PHP 正在调用一个 libxml 函数 xmlXPathEval,它只需要一个字符串和一个上下文,并立即对其求值。 libxml manual for 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,这只是 context,即 "current node" 来比较表达式。 ->eval()->query() 的定义使用相同的 C 实现,php_xpath_eval。这会检查一些内部状态是否正确,然后调用:

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

那是一个不同的函数,所以我们可以 look it up in libxml:

Function: xmlXPathEvalExpression Alias for xmlXPathEval().

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

xmlXPathFreeObject(xpathobjp);

所以,和以前一样:没有显式编译,调用之间唯一存储的是 "context" 用于 运行 反对的 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 对象一样长。

我们可以dig into the implementation of xmlXpathNewContext查看这个缓存是默认启用还是禁用:

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

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