Трейты в PHP

17.05.2018 в 19:46
6647
+33

Как мы знаем, в PHP класс может наследоваться только от одного класса. Но как быть, если мы хотим иметь какой-либо функционал в разных классах, которые не являются наследниками друг друга? Для этого придумали трейты. Трейты в PHP – это такой механизм, который позволяет внутри классов избегать повторного использования кода.

Давайте разберём на примере. Пусть у нас будут два совершенно не связанных между собой класса: коробка и человек. Но предположим, что мы хотели бы, чтобы они оба умели говорить о том, какого они класса. Давайте для начала создадим два этих класса и прямо в них создадим методы sayYourClass(), которые будут выводить имя класса, объектами которого они являются.

<?php

class Man
{
    public function sayYourClass(): string
    {
        return 'My class is Man';
    }
}

class Box
{
    public function sayYourClass(): string
    {
        return 'My class is Box';
    }
}

$man = new Man();
$box = new Box();

echo $man->sayYourClass();
echo $box->sayYourClass();

Результат:

My class is Man
My class is Box

В PHP можно получить имя класса с помощью конструкции ИмяКласса::class. Например:

echo Box::class;

Выведет:

Box

Если мы находимся внутри класса, например, в каком-то его методе, то мы можем ИмяКласса заменить словом self – текущий класс.

<?php

class Man
{
    public function sayYourClass(): string
    {
        return 'My class is ' . self::class;
    }
}

class Box
{
    public function sayYourClass(): string
    {
        return 'My class is ' . self::class;
    }
}

$man = new Man();
$box = new Box();

echo $man->sayYourClass();
echo $box->sayYourClass();

Результат останется прежним.

My class is Man
My class is Box

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

trait SayYourClassTrait
{
    public function sayYourClass(): string
    {
        return 'My class is ' . self::class;
    }
}

Ничего сложного. Теперь мы можем просто использовать этот трейт в двух наших классах. Для этого используется конструкция use.

class Man
{
    use SayYourClassTrait;
}

class Box
{
    use SayYourClassTrait;
}

$man = new Man();
$box = new Box();

echo $man->sayYourClass();
echo $box->sayYourClass();

И снова увидим нужный результат:

My class is Man
My class is Box

Код из трейта SayYourClass просто подставился в классы, где мы его использовали с помощью слова use. В self будет лежать класс, в котором сейчас исполняется этот код. Вот так всё просто.

Трейты также довольно плотно пересекаются с темой интерфейсов.

Давайте добавим интерфейс, который будет обязывать классы иметь метод sayYourClass().

interface ISayYourClass
{
    public function sayYourClass(): string;
}

Теперь наши классы могут его реализовать – этот метод реализован в трейте, а трейт используется в классе.

Давайте посмотрим на получившийся код.

interface ISayYourClass
{
    public function sayYourClass(): string;
}

trait SayYourClassTrait
{
    public function sayYourClass(): string
    {
        return 'My class is ' . self::class;
    }
}

class Man implements ISayYourClass
{
    use SayYourClassTrait;
}

class Box implements ISayYourClass
{
    use SayYourClassTrait;
}

$man = new Man();
$box = new Box();

echo $man->sayYourClass();
echo $box->sayYourClass();

В PHP класс может наследоваться только от одного класса, помните? Так вот с помощью интерфейсов и трейтов мы можем это ограничение немного обойти. Мы теперь можем добавлять некоторый функционал в классы, которые не имеют какого-то общего поведения в целом. Но они при этом объединены одним интерфейсом. А проверять, реализует ли объект интерфейс, мы уже умеем – с помощью конструкции instanceof.

Таким образом, мы можем обходить ограничения наследования:

  • класс реализует что-то, и мы можем быть в этом уверены (проверив на реализацию интерфейса);
  • класс может иметь несколько таких независимых друг от друга реализаций (благодаря возможности реализовать несколько интерфейсов и подключить несколько трейтов).
loader
17.05.2018 в 19:46
6647
+33
Комментарии
К этому посту больше нельзя оставлять новые комментарии
Логические задачи с собеседований