为什么从未调用过ArrayIterator子类的构造函数?

Wes*_*ter 13 php iterator

我很困惑为什么一个子类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() ) );
}
Run Code Online (Sandbox Code Playgroud)

在PHP 5.4和5.5中,结果是FAIL.为什么?

Jay*_*aph 2

@Leggendario 说问题出在spl_array_object_new_ex方法上是正确的。但是,如果这是一个错误,我不确定。然而,这里发生的事情并不是真正标准的。

iteratorClass构造函数中的变量(或通过设置)setIteratorClass表明,每当我们从 中检索迭代器时,都会实例化此类ArrayObject。但它不会进行常规的“实例化”,因为这是不可能的。

它只会初始化迭代器(分配内存等),但不会调用构造函数。不调用构造函数是有意义的,因为 an 的构造函数ArrayIterator需要两个参数($array$flags),并且您的类可能已更改其签名,甚至可能添加更多(强制值)。

通常,ArrayIterator(或RecursiveArrayIterator) 是内部类,并且附加有一个内部结构(基本上就像它自己的内部属性集,您无法直接从 PHP 用户区访问它们)。将spl_array_object_new_ex直接设置这些内部值(最值得注意的是ce_get_iteratorar_flags)。所以基本上它接管了 ArrayIterator 构造函数的工作。

因为 PHP 检查给定的类是否为ArrayIterator,或者父类之一是否为 。当这样时,这意味着它最终可以使用这些内部值,从而直接设置它们,绕过对构造函数的任何需要。缺点是,您想要自己构建的任何内容都不会被调用。