Почему PHP Trait не может реализовать интерфейсы?


мне интересно, почему PHP Trait (PHP 5.4) не может реализовать интерфейсы.

обновление от ответа пользователя 1460043=>...не может требовать класс, который использует его для реализации определенного интерфейса

Я понимаю, что это может быть очевидно, потому что люди могут думать, что если Class A использует Trait T который реализует interface I, чем Class A должна быть реализация interface I undirectly (и это не так, потому что Class A может переименовать методы признака).

в моем случае мой признак вызывает методы из интерфейса, который реализует класс, использующий признак.

признак на самом деле является реализацией некоторых методов интерфейса. Итак, я хочу "спроектировать" в коде, что каждый класс, который хочет использовать мою черту, должен реализовать интерфейс. Это позволит черте использовать методы класса, определенные интерфейсом, и убедиться, что они существуют в классе.

3 65

3 ответа:

очень короткий вариант проще, потому что вы не можете. Это не как черты характера работ.

когда вы пишите use SomeTrait; в PHP вы (фактически) говорите компилятору скопировать и вставить код из признака в класс, где он используется.

потому что use SomeTrait; находится внутри класса, он не может добавить implements SomeInterface к классу, потому что это должно быть вне класса.

" почему в PHP нет типов признаков? "

потому что они не могут быть инстанцирован. Черты действительно просто языковая конструкция (указание компилятору скопировать и вставить код признака в этот класс) В отличие от объекта или типа, на который может ссылаться ваш код.

Итак, я хочу "дизайн" в коде, что каждый класс, который хочет использовать моя черта должна реализовать интерфейс.

это может быть применено с помощью абстрактного класса к use в черта, а затем расширение классов от нее.

interface SomeInterface{
    public function someInterfaceFunction();
}

trait SomeTrait {
    function sayHello(){
        echo "Hello my secret is ".static::$secret;
    }
}

abstract class AbstractClass implements SomeInterface{
    use SomeTrait;
}

class TestClass extends AbstractClass {
    static public  $secret = 12345;

    //function someInterfaceFunction(){
        //Trying to instantiate this class without this function uncommented will throw an error
        //Fatal error: Class TestClass contains 1 abstract method and must therefore be 
        //declared abstract or implement the remaining methods (SomeInterface::doSomething)
    //}
}

$test = new TestClass();

$test->sayHello();

однако-если вам нужно обеспечить, чтобы любой класс, который использует признак, имел определенный метод, я думаю, что вы можете использовать черты, где вы должны были быть абстрактными классами в первую очередь.

или что у вас есть ваша логика навыворот. Вы должны требовать, чтобы классы, реализующие интерфейсы, имели определенные функции, а не то, что если у них есть определенные функции, которые они должны объявить себя как реализующие взаимодействие.

Edit

на самом деле вы можете определить абстрактные функции внутри признаков, чтобы заставить класс реализовать метод. например,

trait LoggerTrait {

    public function debug($message, array $context = array()) {
        $this->log('debug', $message, $context);
    }

    abstract public function log($level, $message, array $context = array());
}

однако это все еще не позволяет реализовать интерфейс в черте, и все еще пахнет плохим дизайном, поскольку интерфейсы намного лучше, чем черты при определении контракта, который должен выполнить класс.

здесь RFC: черты с интерфейсами предлагает добавить в язык следующее:

trait SearchItem implements SearchItemInterface
{
    ...
}

методы, требуемые интерфейсом, могут быть либо реализованы признаком, либо объявлены как абстрактные, и в этом случае ожидается, что класс, использующий признак, реализует его.

эта функция в настоящее время не поддерживается языком, но она находится на рассмотрении (текущий статус RFC: Обсуждается).

[...] чтобы "дизайн" в коде, что каждый класс, который хочет использовать мою черту придется реализовать интерфейс. Это позволило бы признак, чтобы использовать методы класса определяется интерфейсом и убедитесь, что они существуют в классе.

это звучит очень разумно, и я бы не сказал, что должно быть что-то не так с вашим дизайном. Черты были предложены с этой идеей в виду, см. Второй пункт здесь:

  • черта предоставляет набор методов, реализующих поведение.
  • признак требует набор методов, которые служат в качестве параметров для указанного поведения.
  • [...]

Schärli et al, черты характера: составные единицы поведения, ECOOP ' 2003, LNCS 2743, PP. 248-274, Springer Verlag, 2003, Page 2

Так было бы, возможно, более уместно сказать, что вы хотите черта требуются интерфейс, а не "реализовать" его.

Я не вижу причины, по которой это должно быть невозможно, чтобы эта "черта требует (ее потребительские классы для реализации) интерфейса" в PHP, но в настоящее время она, похоже, отсутствует.

Как отмечает @Danack в своем ответ, вы можете использовать абстрактные функции в черта, чтобы "требовать" их от классов, которые используют черта. К сожалению, вы не можете сделать это с помощью частная функции.