Php 构建DOMXPath的成本有多高?

Php 构建DOMXPath的成本有多高?,php,xml,dom,xpath,domdocument,Php,Xml,Dom,Xpath,Domdocument,在编写复杂XML文档的解析器时,我想知道是否可以在需要时构造DOMXPath实例: function parseData($d) { $xpath = new DOMXPath($d); // ... } function parseMoreData($d) { $xpath = new DOMXPath($d); // ... } $d = new DOMDocument(); $d->loadXML($xml); parseData($d); par

在编写复杂XML文档的解析器时,我想知道是否可以在需要时构造
DOMXPath
实例:

function parseData($d) {
    $xpath = new DOMXPath($d);
    // ...
}

function parseMoreData($d) {
    $xpath = new DOMXPath($d);
    // ...
}

$d = new DOMDocument();
$d->loadXML($xml);
parseData($d);
parseMoreData($d);
另一种方法是在开始时创建一个
DOMXPath
实例,然后在解析器中的任何地方重用它:

function parseData($d, $xpath) {
    // ...
}

function parseMoreData($d, $xpath) {
    // ...
}

$d = new DOMDocument();
$d->loadXML($xml);
$xpath = new DOMXPath($d);
parseData($d, $xpath);
parseMoreData($d, $xpath);

您的替代方案当然更有效,因为它不会重建一个domXpath。 但您必须记住的是,这里唯一需要的对象是DomXPath。 如您所见,DOMXpath的构造函数只依赖于您提供给他的DOMDocument实例。因此,如果您的函数只使用DOMXpath作为参数,那么它将是相同的

您可以使用
$xpath->document
访问xpath文档

然后,就像你想要的,你赢得的性能不是那么重要,只有252字节

关于所需的时间,只有当您使用大文件时,解析时间才会变得重要,因为解析时间比任何其他处理和每次启动DOMXPath都重要。 解决方案可以是使用工厂模式:

class XPathFactory{
    private static instances=array();
    public static function getXPath($doc,$namespacePrefix){
        if(!isset(self::$instances[spl_object_hash($doc).$namespacePrefix]){
           self::$instances[spl_object_hash($doc).$namespacePrefix] = new DOMXPath($doc);
           self::$instances[spl_object_hash($doc).$namespacePrefix]->registerNamespace($namespacePrefix);
         }
         return self::$instances[spl_object_hash($doc).$namespacePrefix];
    }
 }
然后在函数中,只需调用:

 XPathFactory::getXPath($doc,$namespace);

您将获得良好的XPAth,而不需要太多实例。

在需要时创建
DOMXpath
实例是非常好的,PHP中的这些内置类没有太多开销。尤其是对于DOMDocument/DOMXpath,这些仅仅是围绕libxml的特性

因此,更多的因素是您打开了多少(不同的)文档,而不是您创建了多少
DOMXpath
对象

也可以不将
DOMDocument
传递到解析函数中:

您可以传递xpath—它还携带文档:

function parseData(DOMXpath $xpath) 
{
    $doc = $xpath->document;

    // ...
}
因此,从技术上讲,您的具有两个函数参数的替代示例根本没有必要。因为你只关心那个细节,最后的建议应该能解决你的“问题”

请记住,通常只有在遇到实际问题时才需要关心性能。在这里,代码只是通过注入要操作的对象来改进,而不是在函数内部创建对象。这就是所谓的依赖注入,也是编写代码的一种更好的方法:函数应该询问(读:有一个参数)它们需要什么,而不是自己创建它。他们应该专注于工作(这里是解析数据),而不是首先实例化
DOMXPath


O(1)
(大O表示法)的问题。 新的DOMXpath($doc)有多贵?是不是
O(1)
?在评论中,我根据我的经验和理解回答了是

现在我还研究了lxr。创建新的
DOMXPath
时(),它只是libxml(DOMDocument扩展的底层C库)中结构的包装器


所有这些代码看起来都非常简单,只读取/设置单个值(而不是其他大小列表等等),所以我现在要说是的,创建
DOMXPath
is
O(1)

谢谢!尽管如此,拥有多个
DOMXPath
实例可能更可取,因为我可以以不同的方式注册名称空间。
DOMXPath
是否以任何方式解析文档?您可以独立注册名称空间。DOMXPath总是解析文档。好吧,但是我可能希望对不同的名称空间URI使用相同的名称空间前缀(就像在手边的文档中一样)。因为它是一个对象,所以每次更改名称空间时都是一个引用,所以要为整个对象更改名称空间前缀。所以没关系。我不知道这里有什么要紧的。虽然可以给现有的名称空间前缀分配一个新的URI,但它不会增加可读性。哪个“货币”昂贵?记忆?执行时间?代码行?维修你遇到了什么具体问题?你有没有遇到过任何与昂贵有关的事情正如你所看到的,说出你的要求并不容易,我还是试着回答。请看一看。从我的脑海中:我正在编写一个API接口,该接口返回大小为数十MB的结果(当小于1 MB时就足够了,XML中有很多冗余,包括调试数据)。我们遇到了缓慢。一般来说,我想知道
新的DOMXPath($d)
是否进行任何解析,即执行时间是否取决于文档大小,或者执行时间是否为
O(1)
。好吧,执行实际的
DOMXPath::query
需要时间,但是,如果您认为需要自己遍历XML树,它相当快(取决于xpath查询和文档大小)。另一方面,一个新的
DOMXPath
的实例化在PHP中非常便宜,这也是我开始回答的问题,创建许多这样的实例是可以的——但是,正如我随后总结的,对于您给出的代码示例,您不应该这样做,因为解析方法应该使用依赖项注入,而不是创建自己的xpath:)您可以在回答中添加
new DOMXPath($d)
的执行时间,具体取决于文档大小吗
O(1)
?如果
O(1)
意味着无论文档有零个节点还是十万个节点,它都需要相同的时间,那么它必须是
O(1)
。请注意,这仅适用于
新的DOMXPath($doc)
,不适用于运行xpath查询(!)。是的,我的意思是运行时间取决于输入数据量。你能在你的答案中添加你的评论吗?@feklee:编辑了答案,并提供了一些对底层源代码的更多参考,这些源代码应该在我谈论体验时进行更多的备份。它还向您展示了如何自己研究细节。我也忘了链接这个,它是libxml2中的constructor-我只在答案中链接了struct:-正如您所看到的,这是非常直接的。
function parseData(DOMXpath $xpath) 
{
    $doc = $xpath->document;

    // ...
}