首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >为什么ArrayIterator子类的构造函数从未被调用?

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

Stack Overflow用户
提问于 2015-05-22 23:47:52
回答 2查看 583关注 0票数 13

我感到困惑的是,为什么ArrayIterator的子类从未被调用过它的__construct方法。考虑一下这个例子:

代码语言:javascript
复制
<?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。为什么?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 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_iteratorar_flags)。因此,基本上它接管了ArrayIterator构造函数的工作。

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

票数 2
EN

Stack Overflow用户

发布于 2015-05-30 21:17:59

方法__construct,通常在创建新实例时调用:

代码语言:javascript
复制
$it = new FooIterator();

因此,这需要一些时间,我有一个解决方案:重写示例中的类Foo (子类ArrayObject)中的getIterator()

代码语言:javascript
复制
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

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/30407398

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档