[英]Why is ArrayIterator subclass's constructor never called?
我很困惑为什么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
。 为什么?
方法__construct通常在创建新实例时被调用:
$it = new FooIterator();
所以,它需要一些时间,我有一个解决方案:在您的类Foo (ArrayObject的子类)中覆盖方法getIterator()到下一个示例:
class Foo extends ArrayObject {
public function __construct( $arr = array(), $flags = 0, $iterator = 'FooIterator' ) {
parent::__construct( $arr, $flags, $iterator );
}
/**
* @return ArrayIterator
*/
public function getIterator()
{
$class = $this->getIteratorClass();
return new $class($this);
}
}
通过此更正,您的代码将“通过”。
来自问题的更改代码的结果:http: //3v4l.org/HnFQm
以前的代码无一例外,但显示迭代器在Foo类中更改了方法getIterator()(通过索引添加和取消设置):http: //3v4l.org/R8PHr
@Leggendario说得对,问题在于spl_array_object_new_ex
方法。 但是,如果这是一个我不确定的错误。 然而,这并不是真正的标准。
构造函数中的iteratorClass
变量(或通过setIteratorClass
设置)表明每当我们从ArrayObject
检索迭代器时,此类都会被实例化。 但它没有定期“实例化”,因为这是不可能的。
它只会初始化迭代器(分配内存等),但不会调用构造函数。 不调用构造函数是有意义的,因为ArrayIterator
的构造ArrayIterator
接受两个参数( $array
和$flags
),并且您的类可能已更改其签名,甚至可能添加更多(强制值)。
通常, ArrayIterator
(或RecursiveArrayIterator
)是内部类,并且内部结构附加到它们(基本上就像它自己的内部属性集,您无法直接从PHP用户区获取)。 spl_array_object_new_ex
将直接设置这些内部值(最值得注意的是ce_get_iterator
和ar_flags
)。 所以基本上它接管了ArrayIterator构造函数的工作。
因为PHP检查给定的类是否是ArrayIterator
,或者其中一个父类是否为1。 这样,它意味着它最终可以使用这些内部值,从而直接设置它们,绕过对构造函数的任何需求。 作为一个缺点,任何你想自己构建的东西都不会被调用。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.