2010-01-03 10 views
7

Se ho una classe genitore estesa da molte e molte altre classi e voglio assicurarmi che il costruttore della classe genitrice sia SEMPRE eseguito, è una cattiva idea dichiarare il costruttore final?È una cattiva pratica dichiarare il termine 'finale' di una classe in PHP?

Stavo pensando di fare qualcosa di simile:

class ParentClass { 

    public final function __construct() { 

     //parent class initialization... 

     $this->construct(); 

    } 

    protected function init() { 

     echo 'constructing<br>'; 

    } 

} 

class ChildClass extends ParentClass { 

    protected function init() { 

     //child class initialization 

     echo 'constructing child<br>'; 

    } 

} 

in questo modo la classe bambino può avere una sorta-di costruttore e di costruzione della classe genitore sarà sempre eseguire. Questa cattiva pratica?

+0

capisco perché non ti fidi di programmatori PHP, ma non capisco il motivo per cui si cura :-) –

+0

Sto solo cercando essere esplicito con il mio codice –

risposta

9

Dichiarare uno final__construct assicura che nessuno che estende la classe possa implementare un metodo con lo stesso nome. Sulla superficie di esso, sembrerebbe che significherebbe che nessun altro può dichiarare un costruttore per le sottoclassi di questa classe, ma questo non è vero, poiché lo stile PHP 4 di ClassName() funziona ancora bene come nome alternativo per il costruttore. Quindi, dichiarare un costruttore come finale non ti porta nulla in PHP.

+0

è vero, non l'avevo considerato.Il metodo '__construct' della classe genitore sarebbe comunque chiamato? Oppure il costruttore della classe bambino di un nome diverso lo sovrascriveva? –

+1

I costruttori principali non vengono mai chiamati automaticamente. Dovresti comunque chiamare 'parent :: __ construct()' o 'parent :: ClassName()' nel costruttore della classe figlio. – Mike

-1

Dopo la finalizzazione del costruttore, non è possibile passare alcuna variabile alla funzione di inizializzazione. Costringe gli utenti della tua classe a utilizzare le globali come impostazioni per le loro classi figlio.

In Zend Framework l'utilizzo di init() sovrascrivibile è una pratica comune, ma non ho mai visto la finalizzazione di un costruttore lì.

+0

Davvero? Ho appena provato e ho potuto passare una variabile dalla funzione di inizializzazione alla funzione di inizializzazione dell'infanzia e farlo eco –

+1

oh, voglio dire, l'utente non può passare alcun parametro unforestore –

+0

Tuttavia, ZF si sta muovendo per aggirare gli oggetti di configurazione come un mezzo di standardizzare il modo in cui i parametri vengono passati tra gli oggetti. –

3

partire da PHP 5.3.3, ho provato questo con 5.6 e 7.0, dichiarando il metodo di una classe final__construct impedirà qualsiasi classe bambino sovrascrivendo il costruttore sia utilizzando __construct o lo stile di PHP 4 ClassName() (notare che il Lo stile PHP 4 è obsoleto a partire da PHP 7). Prevenire una classe figlia che dichiara un costruttore farà in modo che venga sempre chiamato il costruttore genitore. Ciò, ovviamente, non consentirà a nessuna classe figlia di implementare la propria logica di costruzione. Ci sarebbero sicuramente casi d'uso pratico per questo sebbene non lo raccomanderei come buona pratica in generale.

Alcuni esempi:

senza dichiarare __construct finale

class ParentClassWithoutFinal { 
    private $value = "default"; 

    public function __construct() { 
     $this->value = static::class; 
    } 

    function __toString() { 
     return $this->value; 
    } 
} 

class ChildClassA extends ParentClassWithoutFinal { 
    public function __construct() { 
     // Missing parent::__construct(); 
    } 
} 

echo (new ChildClassA()); // ouput: default 

Con finale __construct

class ParentClassWithFinal extends ParentClassWithoutFinal { 
    public final function __construct() { 
     parent::__construct(); 
    } 
} 

class ChildClassB extends ParentClassWithFinal { 
} 

echo (new ChildClassB()); // output: ChildClassB 

Cercando di dichiarare __construct in una classe figlia

class ChildClassC extends ParentClassWithFinal { 
    public function __construct() { 
    } 
} 

// Fatal error: Cannot override final method ParentClassWithFinal::__construct() 

Cercando di dichiarare ClassName() costruttore in una classe figlia

class ChildClassD extends ParentClassWithFinal { 
    public function ChildClassD() { 
    } 
} 

// Fatal error: Cannot override final ParentClassWithFinal::__construct() with ChildClassD::ChildClassD() 
// Also in PHP 7: Deprecated: Methods with the same name as their class will not be constructors in a future version of PHP; ChildClassD has a deprecated constructor