繁体   English   中英

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

[英]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_iteratorar_flags )。 所以基本上它接管了ArrayIterator构造函数的工作。

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM