2012-09-18 24 views
43

En PHP 5, puedo sobrecargar constructores (y cualquier otro método). Pero si me da un poco de código como este:Cómo sobrecargar el constructor de clase dentro de los rasgos en PHP> = 5.4

class Base { 

    public function __construct($a, $b) { 
     echo $a+$b; 
    } 


    public function sayHello() { 
     echo 'Hello '; 
    } 
} 


trait SayWorld { 

    public function __construct($a, $b, $c = 0) { 
     echo (int)$c * ($a+$b); 
    } 

    public function sayHello($a = null) { 
     parent::sayHello(); 
     echo 'World!'.$a; 
    } 
} 

class MyHelloWorld extends Base { 
    use SayWorld; 
} 

$o = new MyHelloWorld(2, 3); 
$o->sayHello(1); 

Tengo un error:

Fatal error: MyHelloWorld has colliding constructor definitions coming from traits

¿Cómo puedo solucionarlo? Puedes probar mi código here.

+1

Solo una advertencia.Los alias de rasgo causarán que PHP se cuelgue a partir de 5.4.7, particularmente con cargadores automáticos. Se ha agregado una solución al repositorio, así que con suerte aparecerá en la próxima versión. – Matthew

Respuesta

81

creo que por ahora la única manera de hacer lo que quiere decir:

class MyHelloWorld extends Base { 

    use SayWorld { 
     SayWorld::__construct as private __swConstruct; 
    } 

    public function __construct($a, $b, $c = 0) 
    { 
     $this->__swConstruct($a, $b, $c); 
    } 
} 

Edición 2:

Mi consejo, basado en más de un año de tratar con el rasgo s en PHP, es: evite escribir constructores en los rasgos, o si debe hacerlo, al menos hágalo sin parámetros. Tenerlos en rasgos va en contra de la idea de constructores en general, que es: Los constructores deben ser específicos de una clase a la que pertenecen. Otros lenguajes de alto nivel evolucionados ni siquiera admiten la herencia implícita de constructores. Esto se debe a que los constructores tienen una relación mucho más fuerte con la clase que con otros métodos. De hecho, tienen una relación tan fuerte, que incluso el LSP no se aplica a ellos. Los rasgos en el lenguaje Scala (un muy maduro y SOLID -friendly successor of Java), can't have a constructor with parameters.

Editar 1:

Había una bug en PHP 5.4.11, que en realidad permite que el alias A método de la superclase. Pero esto fue considerado un no-no por los desarrolladores de PHP, por lo que todavía estamos atrapados con esa solución engorrosa que presenté anteriormente. Pero ese error provocó una discusión sobre lo que se puede hacer con esto, y espero que sea el objetivo en futuras versiones.

Mientras tanto, me encontré con el mismo problema una y otra vez. Mi irritación aumentó exponencialmente con la cantidad de parámetros y líneas de docblock que tuvieron que repetirse muchas veces para usar el rasgo. Así me ocurrió con el patrón siguiente con el fin de adherirse a la regla SECO tanto como pude:

En vez de repetir todo el conjunto de parámetros de la siguiente manera:

trait SayWorld { 

    /** 
    * This is a valid docblock. 
    * 
    * @param int $a Doc comment. 
    * @param int $b Doc comment. 
    */ 
    public function __construct($a, $b) { 
     echo (int)$c * ($a+$b); 
    } 
} 

class MyHelloWorld extends Base { 

    use SayWorld { 
     SayWorld::__construct as private __swConstruct; 
    } 

    /** 
    * Repeated and unnecessary docblock. 
    * 
    * @param int $a Doc comment. 
    * @param int $b Doc comment. 
    * @param int $c Doc comment. 
    */ 
    public function __construct($a, $b, $c = 0) 
    { 
     $this->__swConstruct($a, $b); 
    } 
} 

que escribir una clase muy similar a una tupla (concepto familiar a C# y Python usuarios), y usarlo en lugar de un sinfín de parámetros:

class SayWorldConstructTuple 
{ 
    public $a; 

    public $b; 

    public function __construct($a, $b) 
    { 
     $this->a = $a; 
     $this->b = $b; 
    } 
} 

class MyHelloWorld extends Base { 

    use SayWorld { 
     SayWorld::__construct as private __swConstruct; 
    } 

    /** 
    * New and valid docblock. 
    * 
    * @param SayWorldConstructTuple $Tuple 
    * @param int $c Additional parameter. 
    */ 
    public function __construct(SayWorldConstructTuple $Tuple, $c = 0) 
    { 
     $this->__swConstruct($Tuple->a, $Tuple->b); 
     $this->c = $c; 
    } 
} 

Nota: este patrón es por supuesto más útil con a la cantidad máxima de parámetros de constructor de tupla, y más clases que usan la tupla.

Se puede automatizar aún más con el uso de la naturaleza dinámica de PHP.

+11

+1 para' evitar escribir constructores en rasgos en absoluto' con explicación – Dennis

+0

Genius! Funciona :) – Robert

5

Probar:

use SayWorld { 
    Base::__construct insteadof SayWorld; 
} 

Ref: PHP Docs

+0

* asiente *, agradable +1 – wesside

+0

Lo intenté. ¿Has ** tratado ** de ejecutar tu propio código? Devuelve que MyHelloWorld tiene definiciones de constructores colisionantes que provienen de los rasgos de error fatal de todos modos. –

+0

Lo siento, mi error fue seguro de que lo tenía correcto;) ... ¡Reparado! – Martin

Cuestiones relacionadas