[英]What exactly does PHP SPL RecursiveIterator::getChildren() return?
我正在學習Marcus Boerger的標准PHP庫(SPL)。
我已經實現了自己的RecursiveIterator,通過繼承它實現了Iterator
接口。 它還實現Countable
。
我對current() , getChildren()和hasChildren方法感到困惑。 記錄在: http : //www.php.net/~helly/php/ext/spl/interfaceRecursiveIterator.html
如果
current()
quote:'返回當前元素 ',並且 getChildren()
返回,並引用“ 當前元素的子迭代器” 如果與current()
的情況一樣, 則將當前元素視為當前對象的子代。
然后,肯定是文檔指定了getChildren()實際上會返回所涉及節點的孫代。
因此感到困惑。
<?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()
(作為退出遞歸過程的最終條件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)
的布爾值轉換結果 這是正確的嗎?
規范說了一件事-我從字面上理解。 但是我的實際經驗又說一遍。
我認為說“大孩子”沒有權利。 你只是改變你的參考點從當前迭代的元素 , 在當前迭代器,這使得孩子到孫子女。 我看不出這樣做的充分理由,因為這不是我習慣於spl迭代器的約定。
我建議您堅持使用與您發布的代碼相同的代碼,但是我認為您可能並不了解RecursiveIteratorIterator 。 RecursiveIteratorIterator意味着可以處理調用hasChildren()和getChildren()的復雜性,並在過程中維護適當的迭代器堆棧。 最后,您看到的是層次結構的扁平列表。 您的NodeTreeProcessor類當前正在做這些事情。 然后,您可以只遍歷RecursiveIteratorIterator,然后根據所使用的標志獲得廣度優先或深度優先的迭代。 你不必使用雖然RecursiveIteratorIterator。
另外,考慮在調用getChildren()時返回一個新的外部迭代器 。 否則,您將放棄一次在同一節點上使用多個迭代器進行迭代的可能性,因為迭代器的位置將處於共享狀態。 當前,您正在使用內部迭代器范例,其中數據和迭代狀態都存儲在同一對象中。 外部迭代器從數據中分離迭代狀態,從而使您可以在同一數據段上擁有多個活動迭代器。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.