Разница между трейтами, интерфейсами и абстрактными классами в PHP

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

tl;dr

  • Абстрактный класс может содержать сигнатуры методов, а также общие методы, но не может быть инстанцирован сам по себе. Хорошо подходит для создания общего родителя для обмена между классами.
  • Trait — это группа свойств и методов для повторного использования кода, их можно добавить несколько в один класс. Хорошо подходит для организации и уменьшения количества повторений.
  • Интерфейс — это набор сигнатур методов для обеспечения определенной реализации в классе, к которому они добавляются. Хорошо подходит для добавления структуры и стандартизации.

Хотите узнать больше о каждом из них? Читайте дальше!

Абстрактный класс

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

Допустим, у нас есть классы Cat, Dog и Hamster. Они могут иметь некоторые общие методы и функциональность, поэтому можно создать родительский абстрактный класс для добавления общих методов и обеспечения их реализации в дочерних классах.

Родительский абстрактный класс для этих классов может выглядеть примерно так:

<?php
abstract class Pet
{
    abstract protected function greet();

    public function hasFur()
    {
        return true;
    }
}
Вход в полноэкранный режим Выход из полноэкранного режима

У нас есть абстрактный метод greet(), который заставит любой класс, расширяющий Pet, реализовать этот метод. Затем у нас есть публичный метод hasFur(), который будет доступен любому объекту, созданному из класса, расширяющего этот абстрактный класс.

Итак, теперь мы можем создать класс для определенного вида домашних животных:

<?php
class Cat extends Pet
{
    public function greet()
    {
        return 'Meow!';
    }
}

$cat = new Cat();
$cat->greet(); // Meow!
$cat->hasFur(); // true
Вход в полноэкранный режим Выход из полноэкранного режима

Некоторые выводы об абстрактных классах:

  • Не могут быть инстанцированы сами по себе
  • Абстрактные методы просто объявляют сигнатуру (без функциональности).
  • Используются дочерним классом с помощью extends.
  • Действуют как своего рода частично встроенный класс

Трейт

Трейты — это способ повторного использования кода в нескольких (иногда совершенно несвязанных) классах. В отличие от абстрактных классов, несколько трейтов могут быть использованы в одном классе с помощью оператора use.

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

Например, у нас может быть два трейта HasLegs и HasFins:

<?php
trait HasLegs
{
    public function walk()
    {
        $steps = 0;
        while (true) {
            $steps++;
        }
    }
}
Войти в полноэкранный режим Выход из полноэкранного режима
<?php
trait HasFins
{
    public function swim()
    {
        $laps = 0;
        while (true) {
            $laps++;
        }
    }
}
Войти в полноэкранный режим Выход из полноэкранного режима

Мы продолжаем рассматривать примеры животных, приведенные ранее, поэтому предположим, что у нас есть объект Cat, который явно имеет ноги и может ходить. Мы можем использовать наш признак HasLegs, чтобы дать нашему классу Cat метод walk(), который можно использовать:

<?php
class Cat
{
    use HasLegs;
}

$cat = new Cat();
$cat->walk();
Войти в полноэкранный режим Выйти из полноэкранного режима

Или, что если бы у нас был объект Duck, у которого как бы есть и ноги, и плавники? Мы можем использовать оба признака и дать нашему классу методы walk() и swim():

<?php
class Duck
{
    use HasLegs, HasFins;
}

$duck = new Duck();
$duck->walk();
//or
$duck->swim();
Войти в полноэкранный режим Выйти из полноэкранного режима

Некоторые выводы о трейтах:

  • Идеально подходит для повторного использования кода
  • Реализуется в теле класса с помощью use.
  • В одном классе можно использовать несколько
  • Может иметь как свойства, так и методы

Интерфейс

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

Рассмотрим этот пример интерфейса:

<?php
interface Bug
{
    public function legs();
    public function eyes();
}
Вход в полноэкранный режим Выход из полноэкранного режима

Опять же, здесь нет реализации методов legs() и eyes(), только подпись, что они требуются в классах, включающих этот интерфейс. Таким образом, если мы создадим классы, реализующие наш интерфейс Bug, эти методы должны быть доступны в каждом из них.

<?php
class Spider implements Bug
{
    public function legs()
    {
        return 8;
    }

    public function eyes()
    {
        return 8;
    }
}
Вход в полноэкранный режим Выход из полноэкранного режима
<?php
class Beetle implements Bug
{
    public function legs()
    {
        return 6;
    }

    public function eyes()
    {
        return 2;
    }
}
Войти в полноэкранный режим Выход из полноэкранного режима

Итак, теперь у нас есть два класса, каждый из которых реализует наш интерфейс Bug, и оба должны включать методы legs() и eyes(), а также их собственную (обычно уникальную) реализацию.

Некоторые выводы об интерфейсах:

  • Действуют как чертежи для классов
  • Используются в объявлении класса с помощью implements.
  • В одном классе можно использовать несколько интерфейсов
  • Могут содержать только подписи методов (без свойств).

Завершение

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

Если у вас есть какие-либо вопросы по этой теме или по любой другой, связанной с веб-разработкой, задавайте их в комментариях или пишите мне в Twitter!

Оцените статью
devanswers.ru
Добавить комментарий