SimpleXMLElement 和 SimpleXMLElement::children() 是一回事吗?

Are SimpleXMLElement and SimpleXMLElement::children() the same thing?

考虑以下代码:

<?php
$foo = new SimpleXmlElement(
'<foo>
    <bar>
        <baz id="b1"/>
        <baz id="b2"/>
        <baz id="b3"/>
    </bar>
</foo>
');
echo "<pre>";print_r($foo);echo "</pre><br/>";
echo "<pre>";print_r($foo->children());echo "</pre><br/>";
echo "foo===foo->children():".($foo===$foo->children()?"true":"false")."<br/>";//false
echo "foo==foo->children():".($foo==$foo->children()?"true":"false");//true

print_r 显示 foo 和 foo->children() 的相同内容。 $foo==$foo->children() 为真但 $foo===$foo->children() 为假。 $foo->children() 到底是什么?

official document有个注释可能与这个问题有关,但我无法理解它的确切含义。

Note: SimpleXML has made a rule of adding iterative properties to most methods. They cannot be viewed using var_dump() or anything else which can examine objects.

顾名思义,SimpleXMLElement::children 是一个成员函数,只是 returns 子元素作为来自 SimpleXMLElement class 对象的对象。 它总是 return 一个 'SimpleXMLElement' class 对象,除非节点代表一个属性(id,class 等可以被认为是属性),在这种情况下 null 是 returned.

考虑这个例子

$foo = new SimpleXmlElement(
'<foo>
  <bar>
    <baz id="b1">b1</baz>
    <baz id="b2">b2</baz>
    <baz id="b3">b3</baz>
    <pas id="p1">p1</pas>
  </bar>
 </foo>');
$mainfoo = json_encode($foo); var_dump($mainfoo); // string(50) "{"bar":{"baz":["b1","b2","b3"],"pas":["p1","p2"]}}"
$children = json_encode($foo->children()); var_dump($children ); // string(50) "{"bar":{"baz":["b1","b2","b3"],"pas":["p1","p2"]}}"
$childrenofbar = json_encode($foo->bar->children()); var_dump($childrenofbar ); //string(42) "{"baz":["b1","b2","b3"],"pas":["p1","p2"]}"
$children_bar_pas = json_encode($foo->bar->pas); var_dump($children_bar_pas); //string(45) "{"@attributes":{"id":"p1"},"0":"p1","1":"p2"}"

我们不能使用var_dump查看和验证SimpleXmlElement 对象。所以为了方便起见,我们可以简单地 json_encode 它们和 var_dump 它们 ;)

此处第一条语句将 xml/markup 字符串转换为 SimpleXmlElement class 对象。

$foo->children() 将子元素作为 SimpleXmlElement class 对象

$foo->bar->children() 带来 'bar'.

的子元素

根据文档,SimpleXmlElement 的对象可以使用 php 循环(例如 for/foreach 等)进行迭代。

foreach($foo as $f1) {
  var_dump(json_encode($f1)); // "{"baz":["b1","b2","b3"],"pas":["p1","p2"]}"
}

foreach($foo->children() as $f2) {
  var_dump(json_encode($f2)); // string(42) "{"baz":["b1","b2","b3"],"pas":["p1","p2"]}"
}

children() 方法也可用于访问具有有效命名空间的标记的子元素。请参阅 documentation!

中的示例 #2

尽管名称如此,SimpleXMLElement class 的实例可以代表一些不同的事物:

  • 单个 XML 元素;在您的示例中,$foo 表示 XML 文档
  • 根目录中的 <foo> 元素
  • XML 个同名元素的集合;例如,$foo->bar 为您提供一个对象,其中包含所有名为 bar
  • 的子元素
  • 具有不同名称但相同父级的XML个元素的集合;这就是 ->children() 给你的
  • 单个XML 属性$foo->bar[0]->baz[0]['id'] 将为您的示例中第一个 bazid 属性提供一个对象
  • 同一元素上 XML 个属性的集合;这就是 ->attributes() 给你的

很多时候,您实际上并没有注意到自己拥有哪些,​​因为各种 short-hands 让您可以互换对待它们;例如:

  • 属性、方法和对元素和属性集合的属性调用通常引用集合中的第一个元素。所以 $foo->bar->baz['id']$foo->bar[0]->baz[0]['id']
  • 相同
  • 相反,将 foreach 循环与表示单个节点的对象一起使用会自动遍历该元素的子元素,就好像您调用了 ->children()

然而,有时您需要区分。例如,foreach ( $foo->bar as $item ) 将遍历所有名为 bar 的元素;但是 foreach ( $foo->bar->children() as $item ) 将访问名为 barfirst 元素,并遍历 它的 个子元素。

children()方法也用于命名空间之间的切换,见