我困惑为什么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_iteratorar_flags)。因此,基本上,它接管了ArrayIterator构造函数的工作。

因为PHP检查给定的类是ArrayIterator还是父类之一。在这种情况下,这意味着它最终可以使用这些内部值,从而直接设置它们,而无需任何构造函数。不利的一面是,您想要构建的任何东西都不会被调用。

关于php - 为什么从未调用ArrayIterator子类的构造函数?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/30407398/

10-09 18:07