Реализация метода абстрактных черт в PHP - PullRequest
0 голосов
/ 16 мая 2018

У меня есть класс, который выглядит как это .Я также вставлю его ниже для справки:

<?php

trait T1
{
    abstract protected function _doStuff();
}

trait T2
{
    protected function _doStuff()
    {
        echo "Doing stuff in trait\n";
    }
}

class C
{
    use T1 {
        _doStuff as _traitDoStuff;
    }

    use T2 {
        _doStuff as _traitDoStuff;
    }

    protected function _doStuff()
    {
        echo "Doing stuff in class\n";

        $this->_traitDoStuff();
    }
}

Вот что здесь происходит:

  1. T1::_doStuff() используется, и псевдоним _traitDoStuff().Согласно PHP документам, это не переименовывает метод, а только добавляет псевдоним.Таким образом, на данный момент и _doStuff(), и _traitDoStuff() существуют как абстрактно защищенные методы. Используется
  2. T2::_doStuff() и псевдоним _traitDoStuff().В соответствии с PHP документами, из-за приоритета, оба переопределяются методами T2.Так что на данный момент T1::_doStuff() больше не существует.Даже если бы это было так, это было бы реализовано T2::_doStuff().
  3. C реализует _doStuff(), что вызывает _traitDoStuff().На этом этапе, независимо от того, какая реализация _doStuff() используется, очевидно, что этот метод реализован, поэтому контракт, определенный с помощью T1::_doStuff(), выполнен или не существует.

И все же, когда я запускаю это, он выдает следующую ошибку:

Неустранимая ошибка: класс C содержит 1 абстрактный метод и поэтому должен быть объявлен как абстрактный или реализовать оставшиеся методы (C :: _ doStuff)

Как видно из 3v4l, это проявляется везде от PHP 5.4 до 7.2, что намекает на то, что это не ранняя ошибка.Может кто-нибудь, пожалуйста, объясните мне это?

Обновление

Видимо, я просто забыл указать метод псевдонима, то есть T1::_doStuff as _traitDoStuff.

Ответы [ 2 ]

0 голосов
/ 16 мая 2018

Отсутствие операторов разрешения области видимости (T1:: и T2::) скрывало более глубокую проблему.Рассмотрим эти более простые случаи :

trait A {                                                                        
    abstract public function foo();                                              
}                                                                                

class B {                                                                        
    use A; // works                                                              
    public function foo() {}                                                     
}                                                                                

class C {                                                                        
    use A { A::foo as traitFoo; } // works, provided this:                       
    public function traitFoo() {} // <-- is present                              
    public function foo() {}                                                     
}                                                                                

class D {                                                                        
    use A { A::foo as traitFoo; } // does not work by itself                     
    public function foo() {}                                                     
}                                                                                

Что на самом деле происходит: наложение абстрактного метода вводит еще один абстрактный метод в вашем классе.Сообщение об ошибке движка PHP.net сильно вводит в заблуждение:

Неустранимая ошибка: класс D содержит 1 абстрактный метод и поэтому должен быть объявлен абстрактным или реализовать оставшиеся методы (D :: foo)

Но механизм HHVM гораздо более информативен:

Неустранимая ошибка: необработанная ошибка: класс D содержит абстрактный метод (traitFoo) и поэтому должен быть объявлен абстрактным или реализовать оставшиеся методы

RFC по горизонтальному повторному использованию (также известная как Trait) явно не обсуждает этот случай, так что это, возможно, ошибка.Не стесняйтесь сообщать об этом на bugs.php.net .


Так почему же добавление оператора разрешения классов это исправило?

Когда вы добавили класс-операторы разрешения области действия, которые содержали:

use T2 { T2::_doStuff as _traitDoStuff; }

вы удовлетворяли «фантому» abstract protected function _traitDoStuff, введенному:

use T1 { T1::_doStuff as _traitDoStuff; }

Если вы удалили псевдоним, например, use T2; илиuse T2 { T2::_doStuff as _anotherMethod; } вы увидите тот же сбой.

0 голосов
/ 16 мая 2018

Может быть, что-то подобное?

<?php

trait T1
{
    abstract protected function _doStuff();
}

trait T2
{
    protected function _doStuff()
    {
        echo "Doing stuff in trait\n";
    }
}

class C
{
    use T1 {
        T1::_doStuff as _traitDoStuff;
    }

    use T2 {
        T2::_doStuff as _traitDoStuff;
    }

    protected function _doStuff()
    {
        echo "Doing stuff in class\n";

        $this->_traitDoStuff();
    }
}
...