Вместе с классами в PHP широко используется языковая конструкция "интерфейс". В этом уроке мы рассмотрим техническую сторону вопроса, а потом поговорим о смысле. Про последнее я сейчас могу сказать немного, потому что полноценный разговор про суть интерфейсов у нас пойдёт во время изучения полиморфизма в последующих курсах. А пока достаточно иметь общее представление об интерфейсах, так как без них не получится окунуться во фреймворки.
Интерфейс в PHP — конструкция языка, описывающая абстрактный тип данных (АТД). Напомню, что АТД определяет набор операций (функций), независимых от конкретной реализации типа (в нашем случае класса) для манипулирования его значениями. На практике интерфейсы содержат определения функций (то есть описание их сигнатур) без реализации.
Хотя данная конструкция для нас в новинку, само понятие интерфейса используется на протяжении всего курса. В первую очередь это рассуждения о типах. Для оперирования точками на плоскости нам не нужна "реализация" точек. Достаточно того, что мы представляем их визуально и знаем операции, выполняемые над ними. То же самое касается и более базовых концепций, например, чисел и любых арифметических операций. Задумывались ли вы над тем, как на самом деле выполняются арифметические операции? Ответ на этот вопрос гораздо сложнее, чем может показаться на первый взгляд, и он зависит не только от языка, но и от конкретного аппаратного обеспечения (железа). Однако незнание ответа не мешает нам пользоваться числами, строками и массивами, не зная их устройства.
<?php
// file: DecartPointInterface.php
namespace App;
// Интерфейсы, по аналогии с классами, хранятся в своих собственных файлах
// и загружаются автоматически при следовании стандарту PSR-4.
// Имя интерфейса может быть любым, главное — соответствие PSR-4.
interface DecartPointInterface
{
public function __construct($x, $y);
public function getX();
public function getY();
}
То, что раньше мы описывали словами и держали в голове, теперь явно записано в виде кода. Декартова точка — это АТД с тремя операциями:
- Создание точки из двух значений
- Извлечение координаты X
- Извлечение координаты Y
По сути, прикладному коду больше ничего знать о точках и не нужно. Естественно, если нам понадобятся новые операции, то мы всегда можем их добавить, тем самым расширив интерфейс. Свои собственные АТД можно менять как угодно и когда угодно, только учтите, что изменение интерфейса обычно приводит к необходимости править код, использующий его.
Сама по себе конструкция Interface
никак не влияет на остальной код. Недостаточно просто создать интерфейс, в этом нет смысла. Интерфейс должен быть реализован, и тогда он начнёт приносить пользу.
<?php
namespace AnotherApp;
// Импорт интерфейса
use App\DecartPointInterface;
class DecartPoint implements DecartPointInterface
{
private $x;
private $y;
// Интерфейсные функции
public function __construct($x, $y)
{
$this->x = $x;
$this->y = $y;
}
public function getX()
{
return $this->x;
}
public function getY()
{
return $this->y;
}
// Не интерфейсные функции
public function __toString()
{
return "({$this->getX()}, {$this->getY()})";
}
}
Реализация интерфейса происходит за счёт ключевого слова implements
, за которым идёт название интерфейса. Интерпретатор проверяет, чтобы в классе были описаны все функции интерфейса и их сигнатуры совпадали, а если это не так, то возникает ошибка. Реализация интерфейса никак не ограничивает возможности по наполнению класса, другими словами, вы можете определять и добавлять в класс все, что хотите, помимо интерфейсных функций.
Насколько наличие интерфейсов критично для PHP программ? Например, можно в любой программе открыть все файлы с классами и удалить часть определения класса, которая описывает реализацию интерфейсов (слово implements
и то, что идёт за ним). После этого не изменится ровным счётом ничего — программа продолжит выполняться так же, как и выполнялась. Но ситуация меняется, если использовать интерфейс в сигнатурах функций и методов вместо классов.
<?php
function compare(DecartPointInterface $point1, DecartPointInterface $point2)
{
// ...
}
Во время выполнения программы PHP проверяет, реализует ли класс соответствующий интерфейс, и если нет, то возникает ошибка. Причём проверка идёт именно на наличие записи implements
в определении класса, а не на факт того, что методы определены (проверка реализации интерфейса гарантирует это).
Такая запись позволяет коду завязываться не на конкретную реализацию точек, а на их интерфейс. Это — ключевая мысль, которую имеет смысл обсуждать подробнее вместе с полиморфизмом.
Отдельно стоит сказать, что один класс может реализовывать любое число интерфейсов, в таком случае они описываются через запятую:
<?php
// Пример из библиотеки DS, внутри которой реализованы различные структуры данных в объектном синтаксисе
// https://github.com/php-ds/polyfill/blob/master/src/Stack.php
class Stack implements \IteratorAggregate, \ArrayAccess, Collection
{
// some code
}
Здесь класс Stack реализует сразу три интерфейса. Это значит, что внутри него должны быть реализованы методы всех указанных интерфейсов.
Если у разных интерфейсов окажутся методы с одинаковым названием, но разной сигнатурой, то возникнет ошибка. В таком случае придётся отказаться от одного из интерфейсов либо переделать их (например, переименовать методы)
Интерфейс Countable
В PHP встроен интерфейс Countable, а функция count
умеет работать с любым объектом, реализующим этот интерфейс.
<?php
class Collection implements Countable
{
private $items;
public function __construct($items = [])
{
$this->items = $items;
}
public function count()
{
return sizeof($this->items);
}
}
$coll = new Collection([3, 2, 5]);
print_r(count($coll));
// => 3
https://repl.it/@hexlet/php-introduction-to-php-interfaces-countable
Дополнительные материалы
Остались вопросы? Задайте их в разделе «Обсуждение»
Вам ответят команда поддержки Хекслета или другие студенты
- Статья «Как учиться и справляться с негативными мыслями»
- Статья «Ловушки обучения»
- Статья «Сложные простые задачи по программированию»
- Вебинар «Как самостоятельно учиться»
Для полного доступа к курсу нужен базовый план
Базовый план откроет полный доступ ко всем курсам, упражнениям и урокам Хекслета, проектам и пожизненный доступ к теории пройденных уроков. Подписку можно отменить в любой момент.