簡體   English   中英

PHP SPL RecursiveIterator :: getChildren()到底返回什么?

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM