How to overload class constructor within attributes in PHP> = 5.4

In PHP 5, I can overload constructors (and any other methods). But if I get some code:

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

I have an error:

Fatal error: MyHelloWorld has conflicting constructor definitions based on attributes

How can i fix this? You can check my code here .

+55
php traits
Sep 18
source share
3 answers

I think now the only way to do what you want is:

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

Edit 2:

My advice, based on over a year of working with traits in PHP, is this: avoid writing constructors in traits at all , or if you should - at least make them without parameters. Their presence in features contradicts the idea of ​​constructors as a whole, namely: constructors must be specific to the class to which they belong. Other, developed, high-level languages ​​do not even support implicit constructor inheritance. This is because constructors have a much stronger relationship to the class than other methods. In fact, they have such a strong relationship that even LSP does not apply to them. Traits in the Scala language (very mature and SOLID is the friendly successor to Java) cannot have a constructor with parameters .

Change 1:

There was a bug in PHP 5.4.11 that actually allowed the alias to use the superclass method. But the PHP developers considered this a no-no, so we still stick to this cumbersome solution that I presented above. But this mistake raised a discussion about what can be done with it, and I hope that it will be aimed at future releases.

Meanwhile, I came across the same problem over and over again. My irritation increased exponentially with the number of parameters and docblock lines that had to be repeated many times in order to use this trait. So I came up with the following scheme to adhere to the DRY rule as far as I could:

Instead of repeating the whole set of such parameters:

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

I am writing a class that looks like a tuple (the concept is familiar to C # and Python ) and use it instead of an infinite list of parameters:

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

Note: this template, of course, is more useful with a large number of tuple constructor options and more classes using a tuple.

It can be further automated using the dynamic nature of PHP.

+99
Sep 25 '12 at 13:05
source share

Try:

 use SayWorld { Base::__construct insteadof SayWorld; } 

Link: PHP Docs

+6
Sep 18
source share

Old post, but in case this helps someone:

I had a similar situation, but I decided to use a slightly different approach. I wrote a plugin for WordPress and wanted to convey information about the plugin (version, name, text domain, etc.), but I didn’t want to change each file when refactoring or expanding another class, so I created a trait using the constructor, it just calls the init function for class specific operations.

 trait HasPluginInfoTrait{ public function __construct() { $this->plugin_name = PLUGIN_NAME; $this->version = PLUGIN_VERSION; if ( method_exists( $this, 'init' ){ $this->init(); } } } class SampleClass { use HasPluginInfoTrait; private function init(){ // Code specific to SampleClass } } 
0
Jul 22 '19 at 19:48
source share



All Articles