PHP - 我可以获取对象而不是方法 return 吗?

PHP - Can I get the object instead of the method return?

假设我想将 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->createElement("div") return编辑了一个空的 "div" DOMNode,appendChild() 接受它没有问题。

但在第二种情况下,$dom->createElement("div")->appendChild($dom->createTextNode("foobar")) returns 已经附加 "foobar" DOMText。所以 "div" DOMNode 没有被追加,并且 php 抛出警告。

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

我的问题是,有没有办法让方法链到 return 原始修改的(附加了 DOMText)DOMNode,它是由 createElement() return编辑的?

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

谢谢。

Fiddle: http://codepad.org/PFB3Ns7E

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

基本上,您创建了两个模仿 DOMDocumentDOMNode 行为的代理 class,称为 DOMDocumentPlusDOMNodePlus。每个class里面有一个私有的link给真正的class,通过使用魔术方法__call,我们可以委托几乎所有调用原始 classes 的方法。然后当 appendChild 在你的 DOMNodePlus 元素上调用时,你 return $this 而不是 child.

DOMDocumentPlus class

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

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();

是的,首先附加 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>

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