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 以满足您的需求。
基本上,您创建了两个模仿 DOMDocument
和 DOMNode
行为的代理 class,称为 DOMDocumentPlus
和 DOMNodePlus
。每个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>
但不要过度使用它。像这样的长链接不容易维护。
假设我想将 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 以满足您的需求。
基本上,您创建了两个模仿 DOMDocument
和 DOMNode
行为的代理 class,称为 DOMDocumentPlus
和 DOMNodePlus
。每个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>
但不要过度使用它。像这样的长链接不容易维护。