2012-09-18 6 views
43

W PHP 5 mogę przeciążyć konstruktory (i inne metody). Ale jeśli trochę kodu:Jak przeciążyć konstruktor klasy w obrębie cech w PHP> = 5.4

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

mam błąd:

Fatal error: MyHelloWorld has colliding constructor definitions coming from traits

Jak mogę to naprawić? Możesz przetestować mój kod here.

+1

Tylko ostrzeżenie.Aliasy atrybutów spowodują awarię PHP od wersji 5.4.7, szczególnie w przypadku autoloaderów. Poprawka została dodana do repozytorium, więc mam nadzieję, że pojawi się w następnej wersji. – Matthew

Odpowiedz

81

myślę na razie jedynym sposobem na to, co chcesz:

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:

Moja rada, oparta na ponad roku radzenia sobie z cechą s w PHP, to: unikaj pisania konstruktorów o cechach w ogóle, lub jeśli musisz - przynajmniej spraw, by były bez parametrów. Posiadanie ich w cechach jest sprzeczne z ideą konstruktorów w ogóle, która jest: konstruktorzy powinni być specyficzni dla klasy, do której należą. Inne, rozwinięte języki wysokiego poziomu nawet nie obsługują niejawnego dziedziczenia konstruktora. Dzieje się tak, ponieważ konstruktory mają o wiele silniejszy związek z klasą niż inne metody. W rzeczywistości mają tak silną relację, że nawet LSP nie ma do nich zastosowania. Cechy w języku Scala (bardzo dojrzały i SOLID -przyjazny następca Javy), can't have a constructor with parameters.

Edit 1:

Było bug w PHP 5.4.11, która faktycznie pozwoliło aliasu metody nadklasy. Ale to zostało uznane za nie-nie przez programistów PHP, więc nadal utknęliśmy w tym kłopotliwym rozwiązaniu, które przedstawiłem powyżej. Ale ten błąd wywołał dyskusję o tym, co można z tym zrobić, i mam nadzieję, że zostanie skierowany w przyszłych wydaniach.

Tymczasem natknąłem się na ten sam problem w kółko. Moja irytacja rosła wykładniczo wraz z liczbą parametrów i linii docblocka, które musiały być powtarzane wiele razy, aby móc korzystać z tej cechy. Więc wymyśliłem następujący wzór w celu trzymać się reguły DRY jak mogłem:

zamiast powtarzać cały zestaw parametrów tak:

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

napisać klasę podobnie jak krotka (koncepcja znana C# i Python użytkowników) i używać go zamiast niekończącej się listy parametrów:

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

Uwaga: ten wzór jest oczywiście bardziej przydatne z la większa ilość parametrów konstruktora krotki i więcej klas za pomocą krotki.

Można go dalej zautomatyzować za pomocą dynamicznej natury PHP.

+11

+1 dla' unikaj pisania konstruktorów na wszystkich cechach 'z wyjaśnieniem – Dennis

+0

Geniusz! To działa :) – Robert

5

Spróbuj:

use SayWorld { 
    Base::__construct insteadof SayWorld; 
} 

Ref: PHP Docs

+0

* kiwa głową *, miło +1 – wesside

+0

Próbowałem. Czy ** ty próbowałeś uruchomić swój własny kod? Zwraca MyHelloWorld i tak koliduje z definicjami konstruktorów pochodzącymi od błędów krytycznych. –

+0

Przepraszam, mój błąd był przekonany, że mam to wszystko we właściwy sposób;) ... Naprawiono! – Martin