Programing

PHP의 트레이 트 내에서 클래스 생성자를 오버로드하는 방법> = 5.4

lottogame 2020. 12. 30. 07:36
반응형

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 :

1 년 넘게 PHP에서 트레이 트를 다룬 것에 기반한 필자의 조언은 : 트레이 트에 생성자를 전혀 작성하지 않거나 최소한 매개 변수없이 만들어야한다는 것입니다. 그것들을 트레이 트에 넣는 것은 일반적으로 생성자의 개념에 위배됩니다. 즉, 생성자는 자신이 속한 클래스에 고유해야합니다 . 다른 진화 된 고급 언어는 암시 적 생성자 상속도 지원하지 않습니다. 이는 생성자가 다른 메서드보다 클래스와 훨씬 더 강한 관계를 갖기 때문입니다. 사실 그들은 너무 강한 관계를 가지고있어서 LSP 조차도 적용되지 않습니다. Scala 언어의 특성 (매우 성숙하고 SOLID 친화적 인 Java의 후속 버전) 은 매개 변수가있는 생성자를 가질 수 없습니다 .

편집 1 :

있었다 PHP 5.4.11에 실제로 슈퍼 클래스 메서드의 별칭을 지정할 수 버그 . 그러나 이것은 PHP 개발자들에 의해 no-no로 간주되었으므로 위에서 제시 한 성가신 솔루션에 여전히 집착합니다. 그러나 그 버그는 이것으로 무엇을 할 수 있는지에 대한 토론을 불러 일으켰고, 나는 그것이 향후 릴리스에서 타깃이되기를 바랍니다.

그 사이에 나는 같은 문제를 계속해서 마주 쳤다. 특성을 사용하기 위해 여러 번 반복해야하는 docblock의 매개 변수와 줄의 수로 인해 자극이 기하 급수적으로 증가했습니다. 그래서 가능한 한 많이 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);
    }
}

I write a class much like a tuple (concept familiar to C# and Python users), and use it instead of an endless 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 pattern is of course more useful with a larger amount of tuple's constructor parameters, and more classes using the tuple.

It can be automated further with the use of PHP's dynamic nature.


Try:

use SayWorld {
  Base::__construct insteadof SayWorld;
}

Ref: PHP Docs


Old post but, in case this helps anyone:

I had a similar situation but decided to use a slightly different approach. I was writing a WordPress plugin and wanted to pass the plugin info around (version, name, text domain etc..) but didn't want to go around changing each file when refactoring or extend another class so I created a trait with a constructor that simply calls an 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
    }
}

ReferenceURL : https://stackoverflow.com/questions/12478124/how-to-overload-class-constructor-within-traits-in-php-5-4

반응형