2011-11-21 13 views
26

Cuando se subclasan objetos y se desea extender el código de inicialización, existen dos enfoques. Reemplazando __construct(), e implementando un método de inicialización que tu constructor de la superclase llama.Práctica recomendada, anulando __construct() versus método init()

Método 1:

class foo 
{ 
    public function __construct ($arg1, $arg2, $arg3) 
    { 
     // Do initialization 
    } 
} 

class bar extends foo 
{ 
    public function __construct ($arg1, $arg2, $arg3) 
    { 
     parent::__construct ($arg1, $arg2, $arg3); 
     // Do subclass initialization 
    } 
} 

Método 2

class foo 
{ 
    public function init() 
    { 
     // Dummy function 
    } 

    public function __construct ($arg1, $arg2, $arg3) 
    { 
     // Do subclass defined initialization 
     $this -> init(); 
     // Do other initialization 
    } 
} 

class bar extends foo 
{ 
    public function init() 
    { 
     // Do subclass initialization 
    } 
} 

La documentación de Zend Framework parece desalentar a los constructores de primer orden y que quiere reemplazar los métodos init, donde esté previsto, pero esto de alguna manera simplemente doesn' me siento bien conmigo Zend también tiende a hacer algunas cosas con las que no estoy contento, así que no estoy seguro si debería usarse como un ejemplo de las mejores prácticas. Personalmente creo que el primer enfoque es el correcto, pero he visto el segundo enfoque con la frecuencia suficiente como para preguntarme si eso es realmente lo que debería estar haciendo.

¿Tiene algún comentario sobre la anulación de __construct? Sé que debes tener cuidado de recordar invocar el constructor de la superclase, pero la mayoría de los programadores deben tenerlo en cuenta.

EDIT: no estoy usando Zend, sólo estoy usando como un ejemplo de una base de código que le anima a utilizar init() en lugar de __construct primordial().

Respuesta

16

Parece que el segundo enfoque es posponer el problema.

Si usted tiene una clase:

class bar2 extends bar // which already extends foo 
{ 
    public function init() 
    { 
    // You should then do anyway: 
    parent::init(); 

    // ... 
    } 
} 

me inclinaría por la primera aproximación también, más lógico y sencillo, ya que la llamada parent::init() o parent::__construct() no pudo evitarse sin fin. El primer enfoque, IMO, es menos confuso.

3

En primer lugar

Zend también tiende a hacer algunas cosas que no estoy feliz con

Puede resolver esto simplemente, por no usarlo.

Pero en segundo lugar y más importante que debe pasar por encima init() y no __construct() porque init() es parte de la operación de despacho que utiliza Zend y su uso se asegura de que el resto de su aplicación está ahí y en su lugar. De lo contrario, se rompe el flujo del modelo MVC de Zend y puede dar lugar a un comportamiento extraño.

Editar

Creo que la razón principal para mí es que para otros desarrolladores de tocar el violín. Puede hacer cualquier cosa con init() pero no con __construct() ya que esto necesita ejecutarse correctamente con todos los parámetros correctos en su lugar.

Esto es de la Zend Docs:

Aunque siempre se puede anular el constructor del controlador de acción, que No recomiendo este.Zend_Controller_Action :: _ constructo() realiza algunas tareas importantes, como registrar los objetos de solicitud y respuesta , así como cualquier argumento de invocación personalizado pasado desde el controlador frontal . Si debe anular el constructor, asegúrese de llamar al parent :: _construct ($ request, $ response, $ invokeArgs).

+0

Lo siento, debería haber sido un poco más claro en mi pregunta. No estoy usando Zend, estoy trabajando en un código que planeo lanzar al público en algún momento en el futuro si lo considero útil. Solo estaba usando Zend como ejemplo, ya que tiende a usar el método init, y si un marco principal está haciendo eso, entonces debe haber una razón. (incluso si personalmente no me gusta mucho el framework en cuestión) – GordonM

+0

Ah, cierto. Puede valer la pena editar y poner eso en su pregunta. He editado por respuesta. –

0

puedo ver uno de los beneficios del uso de init() en lugar de __construct(): si los cambios de compás en el constructor, que tendrán que actualizar cada clase derivada para que coincida con la nueva firma.

Si init() no tiene parámetro, esto no sucederá.

+1

¿No sería eso también cierto si tiene una clase con una implementación de init() que se subclasificó? ¿No deberían las subclases también actualizarse para reflejar los cambios en el método init de la superclase? – GordonM

1

Usaría la función init porque si anula el constructor (normalmente) tiene que recordar llamar al constructor padre en la parte superior del constructor de la clase secundaria. Si bien puede estar al tanto de eso, no puede garantizar que otro desarrollador encargado de mantener su aplicación lo sea.

8

Las dos únicas situaciones que puedo pensar en las que tiene sentido usar init() es cuando el constructor no es público, pero debe darles a las personas la oportunidad de influir en la inicialización, p. en un Singleton abstracto (que no desea usar de todos modos). O, como en Zend Framework, cuando se debe asignar adicional (pero no se llama al init() desde el constructor).

Llamar a un método en una subclase de la superclase se llama Template Method, por cierto. El UseCase sería para orquestar un cierto flujo de trabajo pero permitir que el subtipo influya en partes de él. Sin embargo, esto generalmente se hace con métodos regulares. Tenga en cuenta que su constructor no debe orquestar nada más que initialize the object into a valid state.

Definitivamente debe no llamada/oferta init() del constructor para evitar que los desarrolladores tengan que recordar llamar al constructor de supertipo. Si bien puede parecer conveniente, rápidamente arruinará la jerarquía de herencia. También tenga en cuenta que se desvía de la forma en que los objetos generalmente se inicializan y los desarrolladores tienen que aprender este nuevo comportamiento del mismo modo que tienen que aprender a llamar al constructor del supertipo.

+0

No me gustaría estar usando singletons y registros y cosas por el estilo, ya recibo suficiente trabajo y no me facilita la vida :) La solución de inicialización diferida parece que es probablemente el único uso válido real para este acercarse a mí, y aun así tengo la sensación de que debe usarse con moderación. Gracias por los punteros – GordonM

+0

BTW, la respuesta del otro hombre fue aceptada porque sospecho que realmente no necesita el representante en este momento. :) – GordonM

+0

@GordonM meh, y aquí estaba pensando que la respuesta más útil tiene el tic verde: P – Gordon

Cuestiones relacionadas