Вопрос по php, traits – Как перегрузить конструктор класса в чертах в PHP> = 5.4

49

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

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

Fatal error: MyHelloWorld has colliding constructor definitions coming from traits

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

Просто предупреждение. Начиная с версии 5.4.7 псевдонимы свойств приведут к сбою PHP, особенно с автозагрузчиками. В репо было добавлено исправление, так что, надеюсь, оно появится в следующей версии. Matthew

Ваш Ответ

2   ответа
5

Пытаться:

use SayWorld {
  Base::__construct insteadof SayWorld;
}

Ref:PHP Документы

После исправления ваш ответ возвращает логику в состояние, когда черты не использовались. Guy Fawkes
nods, приятно +1
Как это работает? Вместо этого я использовал унаследованный конструктор, поскольку он, похоже, не вызывал столкновения.pastebin.com/zHktB5C0
Извините, моя ошибка была уверена, что я правильно понял;) ... Исправлено!
Я попробовал это. Сделалyou пытался запустить свой собственный код? Он возвращает, что MyHelloWorld в любом случае имеет конфликтующие определения конструкторов, исходящие из фатальной ошибки. Guy Fawkes
94

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:

Мой совет, основанный на более чем годе работы с чертами в PHP:avoid writing constructors in traits at allили, если нужно, - по крайней мере, сделать их без параметров. Наличие их в чертах противоречит идее конструкторов в целом, а именно:constructors should be specific to a class to which they belong, Другие развитые языки высокого уровня даже не поддерживают неявное наследование конструктора. Это потому, что конструкторы имеют гораздо более сильное отношение к классу, чем другие методы. На самом деле они настолько сильны, что дажеLSP к ним не относится. Черты языка Scala (очень зрелые иSOLIDдружественный преемник Java),не может иметь конструктора с параметрами.

Edit 1:

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

Между тем я сталкивался с одной и той же проблемой снова и снова. Мое раздражение увеличилось в геометрической прогрессии с количеством параметров и строк докблока, которые пришлось много раз повторять, чтобы использовать эту черту. Поэтому я придумал следующую схему, чтобы максимально придерживаться правила СУХОЙ:

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

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

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

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.

Хороший обходной путь! Большое спасибо!
+1 заavoid writing constructors in traits at all с объяснением
Genius! Оно работает :)

Похожие вопросы