【发布时间】:2013-06-30 15:13:40
【问题描述】:
我正在学习 Marcus Boerger 的标准 PHP 库 (SPL)。
我已经实现了我自己的 RecursiveIterator,它通过继承实现了Iterator 接口。它还实现了Countable。
我对@987654321@、getChildren() 和hasChildren 方法感到困惑。记录在:http://www.php.net/~helly/php/ext/spl/interfaceRecursiveIterator.html
如果
-
current()quote: '返回当前元素', -
getChildren()返回,我引用,“当前元素的子迭代器”
如果像current() 的情况一样,当前元素 被认为是当前对象的子元素。
然后,文档肯定会指定 getChildren() 实际上返回相关节点的 grandchildren。
因此感到困惑。
<?php
/**
*@desc Represents a node within a hierarchy
*/
class RecursableCountableIterableNode implements RecursiveIterator, Countable
{
public $title;
private $_componentsArray;
private $_iteratorPosition;
/**
*@desc adds component
*/
public function addComponent(
RecursableCountableIterableNode $incomingNodeObj
)
{
foreach ( $this->_componentsArray as $componentNodeObj )
{
if ( $incomingNodeObj === $componentNodeObj )
{
//its is already in there
return;
}
}
//add to the next element of the numerically indexed array
$this->_componentsArray[] = $incomingNodeObj;
}
/**
* @desc RecursiveIterator Interface
*/
/**
* @desc Implements the RecursiveIterator Interface
* @return boolean - Whether or not the node at the current element
* has children.
*
* Note: This method does NOT count the children of this node,
* it counts the components of the node at the *current* element.
* There is a subtle but important difference.
* It could have been better to name
* the interface method 'hasGrandChildren()'.
*/
public function hasChildren()
{
return ( boolean ) count( $this->current() );
}
/**
* @desc Gets the node of the current element which in effect is a container
* for childnodes.
*
* Note: According to the SPL, it does NOT get 'the child elements of
* the current node' ($this->_componentsArray) which was a surprise to me.
*
* @return RecursableCountableIterableNode - the
* sub iterator for the current element
*
*/
public function getChildren()
{
return $this->current();
}
/**
* @desc To adhere to countable interface.
* @returns integer - The number of elements in the compondents array.
*/
public function count()
{
return count( $this->_componentsArray );
}
/**
* Iterator methods
*/
/**
* @desc Rewind the iterator to the first element.
* @return void
*/
public function rewind()
{
$this->_iteratorPosition = 0;
}
/**
* @desc Return the current element.
* @return RecursableCountableIterableNode
*/
public function current()
{
return $this->_componentsArray[ $this->_iteratorPosition ];
}
/**
* @desc Return the key of the current element.
* @return integer
*/
public function key()
{
return $this->_iteratorPosition;
}
/**
* @desc Move forward to the next element.
* @return void
*/
public function next()
{
++$this->_iteratorPosition;
}
/**
* @desc Checks if current position has an element
* @return boolean
*/
public function valid()
{
return isset( $this->_componentsArray[ $this->_iteratorPosition ] );
}
}
在上面的类中,getChildren() 返回一个实现 RecursiveIterator 和 Countable 的对象。因为每个RecursableCountableIterableNode 对象都包含其他RecursableCountableIterableNode 对象的实例。我认为它是一种复合模式。
通过实验,我设法通过使用count()(作为退出递归过程的终止条件)和foreach 来迭代每个节点的子节点,从而对树执行递归操作。
有趣的是,实际上,count 功能隐式执行 hasChildren 操作,foreach 构造隐式执行 getChildren 操作以执行递归遍历。
class NodeTreeProcessor
{
protected $output = '';
public function doProcessingWithNode(
RecursableCountableIterableNode $treeNodeObj
)
{
$this->output .= $treeNodeObj->title;
//Base case that stops the recursion.
if (!( count( $treeNodeObj ) > 0 ))
{
//it has no children
return;
}
//Recursive case.
foreach( $treeNodeObj as $childNode )
{
$this->doProcessingWithNode( $childNode );
}
}
}
鉴于此,我认为为了成为一个实用的 RecursiveIterator,
-
getChildren真的应该返回$this而不是current()的节点,并且 -
hasChildren真的应该返回count($this)的布尔转换结果
是这样吗?
规格说明了一件事 - 我从字面上理解。但我的实践经验说明了另一个问题。
【问题讨论】:
-
getChildren 应该返回包裹在另一个迭代器中的 current()。如果它有孩子
-
感谢您的评论。它确实返回 current() - 但没有像你说的那样包装。我应该澄清
getChildren()确实返回了一个实现RecursiveIterator 和Countable 的对象。每个RecursableCountableIterableNode对象都包含其他RecursableCountableIterableNode对象的实例。我认为它是一种复合模式。我将编辑问题以澄清。 -
@tlens 根据我上面的评论,是否有任何理由将其包装在另一个迭代器中?
-
所以你可以以真正的“递归”方式迭代它们
标签: php oop interface spl recursiveiterator