【问题标题】:PHP - Can I get the object instead of the method return?PHP - 我可以获取对象而不是方法返回吗?
【发布时间】:2015-03-15 17:01:17
【问题描述】:

假设我想将一个 div 附加到一个 DOMDocument。我可以这样做:

<?php
$dom = new DOMDocument();

$dom->appendChild(
    $dom->createElement("div")
);

现在,假设我想向该 div 添加一些文本,所以我尝试:

<?php
$dom = new DOMDocument();

$dom->appendChild(
    $dom->createElement("div")
        ->appendChild( $dom->createTextNode("foobar") )
);

但是等等!现在有问题了!

在第一种情况下,$dom-&gt;createElement("div") 返回了一个空的“div”DOMNode,appendChild() 可以毫无问题地接受它。

但在第二种情况下,$dom-&gt;createElement("div")-&gt;appendChild($dom-&gt;createTextNode("foobar")) 返回已附加“foobar”DOMText。所以“div” DOMNode 不会被附加,php 会抛出一个警告。

Warning: DOMNode::appendChild(): Couldn't fetch DOMText

我的问题是,有没有办法让方法链返回由 createElement() 返回的原始修改(附加 DOMText)DOMNode?​​p>

我知道我可以将 DOMNode 保存到一个变量中,然后将它传递给 appendChild(),但我真的很想看到一个单一的解决方案。

谢谢。

小提琴:http://codepad.org/PFB3Ns7E

【问题讨论】:

  • 你可以使用$dom-&gt;createElement('div', 'foobar');
  • 不完全一样,但是createElement('div', 'foobar')会用给定的文本创建一个元素。
  • 或使用html_entities()
  • @Nikita240 这有什么问题?输出看起来正确。
  • @Nikita240 据我所知没有。 DOMNode::appendChild() 返回添加的节点,因此您可以使用额外的变量并使用DomDocument::createTextNode(),或者使用带有htmlentities() 的单行器。

标签: php domdocument php-5.5


【解决方案1】:

如果您有 PHP 5.6+,则可以使用 spread/splat 运算符 (...) 与魔术方法 __call 结合使用猴子修补类以满足您的需求。

基本上,您创建两个代理类来模仿DOMDocumentDOMNode 的行为,称为DOMDocumentPlusDOMNodePlus。每个类都包含一个指向真实类的私有链接,通过使用魔术方法__call,我们可以将几乎所有调用委托给原始类的方法。然后,当在 DOMNodePlus 元素上调用 appendChild 时,您将返回 $this 而不是子元素。

DOMDocumentPlus

class DOMDocumentPlus {

    private $dom;

    public function __construct(...$args) {
        $this->dom = new DOMDocument(...$args);
    }

    public function __call($name, $args) {
        if($name !== 'createElement') {
            return $this->dom->$name(...$args);
        } else {
            return new DOMNodePlus($this->dom->createElement(...$args));
        }
    }   

}

DOMNodePlus

class DOMNodePlus {

    private $node;

    public function __construct($node) {
        $this->node = $node;
    }

    public function __call($name, $args) {
        if($name !== 'appendChild') {
            return $this->node->$name(...$args);
        } else {
            $this->node->appendChild(...$args);
            return $this->node;
        }
    }

}

主程序

$dom = new DOMDocumentPlus();

$dom->appendChild(
    $dom->createElement("div")->appendChild($dom->createTextNode("foobar"))
);

$dom->formatOutput = true;
echo $dom->saveHTML();

【讨论】:

  • FluentDOM 的即用型库版本 - fluentdom.github.io
  • 这里不需要代理类,你可以扩展现有的DOMDocument(并注册扩展的节点类)。但是你不应该实现与 DOM 标准相冲突的行为。 FluentDOM 既扩展了 DOM,又具有用于创建 XML 的特殊类。
【解决方案2】:

是的,先附加div

$dom = new DOMDocument();

$dom
  ->appendChild(
    $dom->createElement("div")
  )
  ->appendChild( 
     $dom->createTextNode("foobar") 
  );

echo $dom->saveXml();

输出:

<?xml version="1.0"?>
<div>foobar</div>

您可以使用$parentNode 属性再次向上移动。

$dom = new DOMDocument();

$dom
  ->appendChild(
    $dom->createElement("div")
  )
  ->appendChild( 
     $dom->createTextNode("foobar") 
  )
  ->parentNode
  ->appendChild(
     $dom->createElement("span")
  )
  ->appendChild( 
     $dom->createTextNode("FOOBAR") 
  );

echo $dom->saveXml();

输出:

<?xml version="1.0"?>
<div>foobar<span>FOOBAR</span></div>

但不要过度使用它。像这样的长链不容易维护。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-11-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-01-12
    相关资源
    最近更新 更多