Я в сетях:

Облако тегов


Использование трейтов в php

Использование трейтов в php

Вернуться на главную

by root posted 21.11.2016 334

Раздел: Теория и практика PHP Теги: начинающим, практика, трейты, оптимизация

Всем привет, сегодня будем говорить о трейтах и практике их использования.

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

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

 

1. Порядок наследования трейтов

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

Другими словами, метод трейта может переопределить метод предка, но не может переопределить метод класса, в который он встраивается.

class Base {
    public function sayHello() {
        echo 'Hello ';
    }
}

trait SayWorld {
    public function sayHello() {
        parent::sayHello();
        echo 'World!';
    }
}

class MyHelloWorld extends Base {
    use SayWorld;
}

$o = new MyHelloWorld();
$o->sayHello();

Результат: Hello World!

trait HelloWorld {
    public function sayHello() {
        echo 'Hello World!';
    }
}

class TheWorldIsNotEnough {
    use HelloWorld;
    public function sayHello() {
        echo 'Hello Universe!';
    }
}

$o = new TheWorldIsNotEnough();
$o->sayHello();

Результат: Hello Universe!

 

2. Разрешение конфликтов между подключаемыми трейтами

Часто необходимо подключать не один, а несколько трейтов. Здесь нужно знать особенности разрешения конфликтов в именах методов. Если в обоих трейтах есть метод с одинаковым названием, будет fatal error. Во избежание казусов рекомендуется указывать основной или используемый трейт или создавать псевдоним с другим именем. Примеры ниже.

 

trait TaxTool s {
  function calculateTax ( $price ) {
  return 222;
}
trait PriceUtilities (
  private $taxrate = 17;
  function calculateтax ( $price ) {
    return ( ( $ this->taxrate/ 100 ) * $price );
  }
}
class Service {
  use PriceUtilities , TaxTools (
  TaxTools::calculateTax insteadof PriceUtilities;
  // можно дополнить, чтобы не терять второй метод
  PriceUtilities::calculateTax as basicTax ;
}
$u = new Service();
print $u->calculateTax ( 100 ) . " \n" ; 

 

3. Хорошая практика использования трейтов

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

Если же вы все-таки решили использовать трейты в своем коде, то для дальнейшей спокойной поддержки хорошо бы придерживаться следующих принципов:

1) Внедряйте новый метод через трейт только подкрепив его контрактом через интерфейс или абстрактный класс. Кратко можно сформулирвоать так:

 

Любому трейт-методу нужен контракт

2) Не используйте свойства класса-рецепиента в трейтах. При острой необходимости во внешних данных, задействуйте метод, подкрепив его перед этим контрактом с помощью интерфейса или абстрактого класса. Другой вариант - создать абстрактный метод в трейте, а реализовать его в классе-приемнике:

trait testTrait {
    function hello() {
        echo "hello " . $this->getName();
    }
    
    abstract function getName();
}

class HelloImplementation {
    use testTrait;
    
    function getName() {
        return "Mike!";
    }
}

$obj = new HelloImplementation();
$obj->hello();

Кратко данный принцип можно озвучить так:

 

Получай внешние данные через контрактные методы приемника

***

Вот и все на сегодня. С данными принципами ваша жизнь будет гораздо легче)

Спасибо за внимание.

comments powered by Disqus