我困惑为什么ArrayIterator
的子类永远不会调用其__construct
方法。考虑以下示例:
<?php
class ConstructorException extends Exception {}
class Foo extends ArrayObject {
function __construct( $arr = array(), $flags = 0, $iterator = 'ArrayIterator' ) {
$iterator = 'FooIterator';
parent::__construct( $arr, $flags, $iterator );
}
}
class FooIterator extends ArrayIterator {
function __construct( $array = array(), $flags = 0 ) {
throw new ConstructorException( 'HELLO WORLD' ); // I AM NEVER CALLED.
parent::__construct( $array, $flags );
}
}
try {
$f = new Foo( array( 1, 2, 3 ) );
$it = $f->getIterator();
if ( get_class( $it ) !== 'FooIterator' ) {
throw new Exception( 'Expected iterator to be FooIterator.' );
}
die( "FAIL\n" );
} catch ( ConstructorException $e ) {
die( "PASS\n" );
} catch ( \Exception $e ) {
die( sprintf( "ERROR: %s\n", $e->getMessage() ) );
}
在PHP 5.4和5.5中,结果均为
FAIL
。为什么? 最佳答案
@Leggendario是正确的说法,问题出在spl_array_object_new_ex
方法中。但是,如果不确定,我不确定。但是,这并不是真正的标准。
构造函数中的iteratorClass
变量(或通过setIteratorClass
设置)建议,每当我们从ArrayObject
中检索迭代器时,此类便会实例化。但是它不会进行常规的“实例化”,因为这是不可能的。
它只会初始化迭代器(分配内存等),而不会调用构造函数。不调用构造函数是有道理的,因为ArrayIterator
的构造函数需要两个参数($array
和$flags
),并且您的类可能已经更改了其签名,甚至可能添加了更多(强制性值)。
通常,ArrayIterator
(或RecursiveArrayIterator
)是内部类,并且具有连接到它们的内部结构(基本上像它自己的内部属性集一样,您不能直接从PHP用户区获得这些属性)。 spl_array_object_new_ex
将直接设置这些内部值(最值得注意的是ce_get_iterator
和ar_flags
)。因此,基本上,它接管了ArrayIterator构造函数的工作。
因为PHP检查给定的类是ArrayIterator
还是父类之一。在这种情况下,这意味着它最终可以使用这些内部值,从而直接设置它们,而无需任何构造函数。不利的一面是,您想要构建的任何东西都不会被调用。
关于php - 为什么从未调用ArrayIterator子类的构造函数?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/30407398/