動作を使用するテーブルからRecursiveIteratorIterator
反復するために使用するカスタム イテレータを作成しました(たとえば、階層内の各レベルのレコードにカスタム ソートを適用するため)。Doctrine_Collection
NestedSet
私のプロジェクトには、この反復子を利用するモデルがいくつかあるため、次のような基本クラスを作成しました。
/** Base functionality for iterators designed to iterate over nested set
* structures.
*/
abstract class BaseHierarchyIterator
extends RecursiveIteratorIterator
{
/** Returns the component name that the iterator is designed to work with.
*
* @return string
*/
abstract public function getComponentName( );
/** Inits the class instance.
*
* @param $objects Doctrine_Collection Assumed to already be sorted by `lft`.
*
* @throws LogicException If $objects is a collection from the wrong table.
*/
public function __construct( Doctrine_Collection $objects )
{
/** @kludge Initialization will fail horribly if we invoke a subclass method
* before we have initialized the inner iterator.
*/
parent::__construct(new RecursiveArrayIterator(array()));
/* Make sure we have the correct collection type. */
$component = $this->getComponentName();
if( $objects->getTable()->getComponentName() != $component )
{
throw new LogicException(sprintf(
'%s can only iterate over %s collections.'
, get_class($this)
, $component
));
}
/* Build the array for the inner iterator. */
$top = array();
/** @var $object Doctrine_Record|Doctrine_Node_NestedSet */
foreach( $objects as $object )
{
// ... magic happens here ...
}
parent::__construct(
new RecursiveArrayIterator($top)
, RecursiveIteratorIterator::SELF_FIRST
);
}
...
}
サブクラスは次のようになります。
/** Iterates hierarchically through a collection of User objects.
*/
class UserHierarchyIterator
extends BaseHierarchyIterator
{
/** Returns the component name that the iterator is designed to work with.
*
* @return string
*/
public function getComponentName()
{
return UserTable::getInstance()->getComponentName();
}
...
}
@kludge
基本クラスのコンストラクターの上部にあることに注意してください。
/** @kludge Initialization will fail horribly if we invoke a subclass method
* before we have initialized the inner iterator.
*/
parent::__construct(new RecursiveArrayIterator(array()));
基本クラスのコンストラクターの先頭に追加の初期化行を保持している限り、すべてが期待どおりに機能します。
ただし、その行を削除/コメントすると、スクリプトが実行されるとすぐに次のエラーが発生します$component = $this->getComponentName()
。
致命的なエラー: BaseHierarchyIterator::__construct(): UserHierarchyIterator インスタンスは、21 行目の /path/to/BaseHierarchyIterator.class.php で適切に初期化されませんでした。
または、呼び出すコード$this->getComponentName()
(および後続の条件ブロック) を削除しても、コンストラクターは引き続き期待どおりに動作します (コンポーネント名が正しいことを確認するためのチェックを除く)。
このエラーの根本原因は何ですか? この問題のより良い回避策はありますか?
PHP バージョン情報:
PHP 5.3.3 (cli) (ビルド: 2012 年 7 月 3 日 16:40:30) Copyright (c) 1997-2010 PHP グループ Zend Engine v2.3.0、Copyright (c) 1998-2010 Zend Technologies Suhosin v0.9.29、Copyright (c) 2007、SektionEins GmbH