Подтвердить что ты не робот

Как перегрузить конструктор классов в пределах признаков в 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 есть конфликтующие определения конструктора, исходящие из признаков

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

4b9b3361

Ответ 1

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

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 существовал bug, что фактически позволяло псевдониму использовать метод суперкласса. Но разработчики 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);
    }
}

Я пишу класс, похожий на кортеж (понятие знакомо С# и 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.

Ответ 2

Try:

use SayWorld {
  Base::__construct insteadof SayWorld;
}

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

Ответ 3

Старый пост, но, в случае, если это кому-нибудь поможет:

У меня была похожая ситуация, но я решил использовать немного другой подход. Я писал плагин для WordPress и хотел передать информацию о плагине (версию, имя, текстовый домен и т.д.), Но не хотел менять каждый файл при рефакторинге или расширять другой класс, поэтому я создал черту с помощью конструктора это просто вызывает функцию init для операций, специфичных для класса.

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