Cómo sobrecargar el constructor de clase dentro de los rasgos en PHP> = 5.4

En PHP 5, puedo sobrecargar constructores (y cualquier otro método). Pero si obtengo un código como este:

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:

Error fatal: MyHelloWorld tiene definiciones de constructores colisionantes que provienen de rasgos

¿Cómo puedo arreglarlo? Puedes probar mi código aquí .

Creo que por ahora la única forma de hacer lo que quieres es:

 class MyHelloWorld extends Base { use SayWorld { SayWorld::__construct as private __swConstruct; } public function __construct($a, $b, $c = 0) { $this->__swConstruct($a, $b, $c); } } 

Editar 2:

Mi consejo, basado en más de un año de tratar con rasgos en PHP, es: evite escribir constructores en 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 sucesor muy maduro y amigable con SOLID de Java) no pueden tener un constructor con parámetros .

Editar 1:

Hubo un error en PHP 5.4.11, que en realidad permitió alias un método de 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 objective 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í que se me ocurrió el siguiente patrón para mantener la regla DRY tanto como pudiera:

En lugar de repetir todo un conjunto de parámetros como este:

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

Escribo una clase como una tupla (concepto familiar para los usuarios de C # y Python ) y la uso en lugar de una lista interminable 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 una mayor cantidad de parámetros de constructor de tupla y más clases que usan la tupla.

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

Tratar:

 use SayWorld { Base::__construct insteadof SayWorld; } 

Ref: PHP Docs