我感到困惑的是,为什么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() ) );
}在PHP5.4和5.5中,结果都是FAIL。为什么?
发布于 2015-05-28 11:55:49
@Leggendario正确地说,问题在于spl_array_object_new_ex方法。但是,如果它是一个bug,我不确定。然而,这里发生的事情并不完全是标准的。
构造函数中的iteratorClass变量(或通过setIteratorClass设置)建议,每当我们从ArrayObject检索迭代器时,这个类就会被实例化。但是它不执行常规的“实例化”,因为这是不可能的。
它只是初始化迭代器(分配内存等),而不是调用构造函数。不调用构造函数是有意义的,因为ArrayIterator的构造函数包含两个参数($array和$flags),您的类可能已经更改了它的签名,甚至可能添加更多的参数(强制值)。
通常,ArrayIterator (或RecursiveArrayIterator)是内部类,并有一个内部结构附加到它们(基本上就像它自己的内部属性集,您无法直接从PHP获得这些属性)。spl_array_object_new_ex将直接设置这些内部值(最显著的是ce_get_iterator和ar_flags)。因此,基本上它接管了ArrayIterator构造函数的工作。
因为PHP检查给定的类是ArrayIterator,还是父类中的一个。如果是这样的话,这意味着它最终可以使用这些内部值,从而直接设置它们,从而绕过对构造函数的任何需要。作为一个缺点,任何你想要构建自己的东西,都不会被称为。
发布于 2015-05-30 21:17:59
方法__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
https://stackoverflow.com/questions/30407398
复制相似问题