0

在编写复杂的 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);
4

2 回答 2

2

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

那么还有什么更重要的是您打开了多少(不同)文档,而不是DOMXpath您创建了多少对象。

也不是将 a 传递给DOMDocument解析函数:

function parseData(DOMDocument $doc) 
{
    $xpath = new DOMXPath($doc);

    // ...
}

您可以传递 xpath - 它也携带文档:

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

    // ...
}

因此,您的具有两个函数参数的替代示例在技术上根本不需要。由于您只关心该细节,因此最后一个建议应该可以解决您的“问题”。

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


O(1)(大 O 表示法)的问题。

有多贵new DOMXpath($doc)?是O(1)吗?在评论中,根据我从经验和理解中了解到的情况,我给出了肯定的回答。

现在我还研究了lxr。当创建一个新DOMXPath的(PHP-C-Code 中的构造函数DOMDocument)时,它只是 libxml(扩展的底层 C 库)中结构的一个包装器: xmlXPathContext.

所有这些代码看起来都非常简单,并且只读取/设置单个值(不是其他大小列表),所以我现在说是的,肯定会创建一个DOMXPathis O(1)

于 2013-06-23T20:22:09.633 回答
0

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

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

然后,就如你所愿,你赢得的性能不是那么显着,只有 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 而无需进行太多实例化。

于 2013-02-26T12:58:56.390 回答