php - initialisierung - Warum wird der Konstruktor der Array-Unterklasse nie aufgerufen?



c++ objekt initialisieren (2)

Ich bin verblüfft, warum eine Unterklasse zu ArrayIterator nie seine __construct Methode aufgerufen bekommt. Betrachten Sie dieses Beispiel:

<?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() ) );
}

In PHP 5.4 und 5.5 ist das Ergebnis FAIL . Warum?

https://ffff65535.com


@ Leggendario hat Recht zu sagen, dass das Problem in der Methode spl_array_object_new_ex liegt. Wenn es sich jedoch um einen Fehler handelt, bin ich mir nicht sicher. Es ist jedoch nicht wirklich Standard, was hier vor sich geht.

Die iteratorClass Variable aus dem Konstruktor (oder setIteratorClass ) würde vorschlagen, dass diese Klasse instanziiert wird, wenn wir den Iterator vom ArrayObject . Aber es macht keine regelmäßige "Instanziierung", da dies nicht möglich ist.

Es wird nur den Iterator initialisieren (Speicher zuordnen usw.), aber den Konstruktor nicht aufrufen. Es ist sinnvoll, den Konstruktor nicht aufzurufen, da der Konstruktor eines ArrayIterator zwei Argumente ( $array und $flags ) benötigt und Ihre Klasse möglicherweise ihre Signatur geändert hat, möglicherweise sogar mehr (obligatorische Werte).

Normalerweise sind der ArrayIterator (oder RecursiveArrayIterator ) interne Klassen und haben eine interne Struktur, die an sie angehängt ist (im Prinzip wie seine eigenen internen Eigenschaften, die Sie nicht direkt vom PHP-Benutzerland erreichen können). Der spl_array_object_new_ex setzt diese internen Werte direkt (vor allem ce_get_iterator und ar_flags ). Im Grunde genommen übernimmt es die Arbeit des ArrayIterator-Konstruktors.

Weil PHP prüft, ob die angegebene Klasse ein ArrayIterator ist oder ob eine der ArrayIterator eins ist. Wenn dies der Fall ist, bedeutet das, dass es letztendlich diese internen Werte verwenden kann und sie somit direkt setzt, ohne dass ein Konstruktor benötigt wird. Als Nachteil wird alles, was Sie selbst konstruieren möchten, nicht aufgerufen.


Die Methode __construct wurde wie üblich beim Erstellen einer neuen Instanz aufgerufen:

$it = new FooIterator();

Also, es dauert einige Zeit und ich habe eine Lösung: override Methode getIterator () in Ihrer Klasse Foo (Unterklasse von ArrayObject) in Ihrem Beispiel zu nächsten:

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);
    }
}

Mit dieser Korrektur wird Ihr Code "BESTANDEN".

Ergebnis des geänderten Codes aus Frage: http://3v4l.org/HnFQm

Vorheriger Code ohne Ausnahme, der aber zeigt, dass Iterator gut mit Änderungen der Methode getIterator () in der Klasse Foo funktioniert (Hinzufügen nach Index und Unscharfschaltung): http://3v4l.org/R8PHr





iterator