Как перегрузить конструктор классов в пределах признаков в PHP> = 5.4

В PHP 5 я могу перегрузить конструкторы (и любые другие методы). Но если я получу какой-то код:

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

У меня есть ошибка:

Неустранимая ошибка: у MyHelloWorld есть конфликтующие определения конструктора, исходящие из признаков

Как я могу это исправить? Здесь вы можете проверить свой код.

Я думаю, что теперь единственный способ сделать то, что вы хотите:

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

Изменить 2:

Мой совет, основанный на более чем год работы с чертами в PHP, заключается в следующем: избегайте писать конструкторы в чертах вообще , или если вы должны – по крайней мере, сделать их без параметров. Наличие их в чертах противоречит идее конструкторов в целом, а именно: конструкторы должны быть специфическими для класса, к которому они принадлежат . Другие, развитые языки высокого уровня даже не поддерживают неявное наследование конструктора. Это связано с тем, что конструкторы имеют гораздо более сильное отношение к классу, чем другие методы. На самом деле они имеют настолько сильное отношение, что даже LSP к ним не относится. Черты языка Scala (очень зрелый и SOLID- дружественный преемник Java) не могут иметь конструктор с параметрами .

Изменить 1:

В PHP 5.4.11 произошла ошибка , которая фактически разрешала псевдоним метода суперкласса. Но разработчики PHP это считали не-нет, поэтому мы все еще придерживаемся этого громоздкого решения, которое я представил выше. Но эта ошибка подняла дискуссию о том, что с этим можно сделать, и я надеюсь, что она будет нацелена на будущие выпуски.

Тем временем я сталкивался с одной и той же проблемой снова и снова. Мое раздражение экспоненциально возрастало с количеством параметров и линий докблока, которые нужно было повторять много раз, чтобы использовать этот признак. Поэтому я придумал следующую схему, чтобы придерживаться правила DRY настолько, насколько я мог:

Вместо того, чтобы повторять весь набор параметров, таких как:

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

Я пишу класс, похожий на кортеж (концепция, знакомая пользователям C # и Python ) и использую его вместо бесконечного списка параметров:

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

Примечание: этот шаблон, конечно, более полезен с большим количеством параметров конструктора кортежа и большим количеством классов, использующих кортеж.

Его можно дополнительно автоматизировать с использованием динамической природы PHP.

Пытаться:

 use SayWorld { Base::__construct insteadof SayWorld; } 

Ссылка: PHP-документы