Php интерфейсы для чего нужны
Интерфейсы объектов позволяют создавать код, который указывает, какие методы должен реализовать класс, без необходимости определять, как именно они должны быть реализованы. Интерфейсы разделяют пространство имён с классами и трейтами, поэтому они не могут называться одинаково.
Интерфейсы объявляются так же, как и обычные классы, но с использованием ключевого слова interface вместо class . Тела методов интерфейсов должны быть пустыми.
Все методы, определённые в интерфейсах, должны быть общедоступными, что следует из самой природы интерфейса.
На практике интерфейсы используются в двух взаимодополняющих случаях:
- Чтобы позволить разработчикам создавать объекты разных классов, которые могут использоваться взаимозаменяемо, поскольку они реализуют один и тот же интерфейс или интерфейсы. Типичный пример — несколько служб доступа к базе данных, несколько платёжных шлюзов или разных стратегий кеширования. Различные реализации могут быть заменены без каких-либо изменений в коде, который их использует.
- Чтобы разрешить функции или методу принимать и оперировать параметром, который соответствует интерфейсу, не заботясь о том, что ещё может делать объект или как он реализован. Эти интерфейсы часто называют Iterable , Cacheable , Renderable и так далее, чтобы описать их поведение.
Интерфейсы могут определять магические методы, требуя от реализующих классов реализации этих методов.
Замечание:
Хотя они поддерживаются, использование конструкторов в интерфейсах настоятельно не рекомендуется. Это значительно снижает гибкость объекта, реализующего интерфейс. Кроме того, к конструкторам не применяются правила наследования, что может привести к противоречивому и неожиданному поведению.
implements
Для реализации интерфейса используется оператор implements . Класс должен реализовать все методы, описанные в интерфейсе, иначе произойдёт фатальная ошибка. При желании классы могут реализовывать более одного интерфейса, разделяя каждый интерфейс запятой.
Класс, реализующий интерфейс, может использовать для своих параметров имя, отличное от имени интерфейса. Однако, начиная с PHP 8.0, в языке поддерживаются именованные аргументы, и вызывающий код может полагаться на имя параметра в интерфейсе. По этой причине настоятельно рекомендуется, чтобы разработчики использовали те же имена параметров, что и реализуемый интерфейс.
Замечание:
Интерфейсы могут быть унаследованы друг от друга, так же, как и классы, с помощью оператора extends.
Замечание:
Класс, реализующий интерфейс, должен объявить все методы в интерфейсе с совместимой сигнатурой. Класс может реализовывать несколько интерфейсов, которые объявляют метод с одинаковым именем. В этом случае реализация должна следовать правилам совместимости сигнатуры для всех интерфейсов. Таким образом, можно применять ковариантность и контравариантность.
Константы ( Constants )
Интерфейсы могут содержать константы. Константы интерфейсов работают точно так же, как и константы классов. До PHP 8.1.0 они не могли быть переопределены классом или интерфейсом, который их наследует.
Примеры
Пример #1 Пример интерфейса
// Объявим интерфейс ‘Template’
interface Template
<
public function setVariable ( $name , $var );
public function getHtml ( $template );
>
// Реализация интерфейса
// Это будет работать
class WorkingTemplate implements Template
<
private $vars = [];
public function setVariable ( $name , $var )
<
$this -> vars [ $name ] = $var ;
>
public function getHtml ( $template )
<
foreach( $this -> vars as $name => $value ) <
$template = str_replace ( ‘<' . $name . '>‘ , $value , $template );
>
// Это не будет работать
// Fatal error: Class BadTemplate contains 1 abstract methods
// and must therefore be declared abstract (Template::getHtml)
// (Фатальная ошибка: Класс BadTemplate содержит 1 абстрактный метод
// и поэтому должен быть объявлен абстрактным (Template::getHtml))
class BadTemplate implements Template
<
private $vars = [];
public function setVariable ( $name , $var )
<
$this -> vars [ $name ] = $var ;
>
>
?>
Пример #2 Наследование интерфейсов
<?php
interface A
<
public function foo ();
>
interface B extends A
<
public function baz ( Baz $baz );
>
// Это сработает
class C implements B
<
public function foo ()
<
>
public function baz ( Baz $baz )
<
>
>
// Это не сработает и выдаст фатальную ошибку
class D implements B
<
public function foo ()
<
>
Пример #3 Совместимость с несколькими интерфейсами
<?php
class Foo <>
class Bar extends Foo <>
interface A <
public function myfunc ( Foo $arg ): Foo ;
>
interface B <
public function myfunc ( Bar $arg ): Bar ;
>
class MyClass implements A , B
<
public function myfunc ( Foo $arg ): Bar
<
return new Bar ();
>
>
?>
Пример #4 Множественное наследование интерфейсов
<?php
interface A
<
public function foo ();
>
interface B
<
public function bar ();
>
interface C extends A , B
<
public function baz ();
>
class D implements C
<
public function foo ()
<
>
public function bar ()
<
>
Пример #5 Интерфейсы с константами
<?php
interface A
<
const B = ‘Константа интерфейса’ ;
>
// Выведет: Константа интерфейса
echo A :: B ;
class B implements A
<
const B = ‘Константа класса’ ;
>
// Выведет: Константа класса
// До PHP 8.1.0 этот код не будет работать,
// потому что было нельзя переопределять константы.
echo B :: B ;
?>
Пример #6 Интерфейсы с абстрактными классами
<?php
interface A
<
public function foo ( string $s ): string ;
public function bar ( int $i ): int ;
>
// Абстрактный класс может реализовывать только часть интерфейса.
// Классы, расширяющие абстрактный класс, должны реализовать все остальные.
abstract class B implements A
<
public function foo ( string $s ): string
<
return $s . PHP_EOL ;
>
>
class C extends B
<
public function bar ( int $i ): int
<
return $i * 2 ;
>
>
?>
Пример #7 Одновременное расширение и внедрение
// Порядок ключевых слов здесь важен. «extends» должно быть первым.
class Two extends One implements Usable , Updatable
<
/* . */
>
?>
Интерфейс, совместно с объявлениями типов, предоставляет отличный способ проверки того, что определённый объект содержит определённый набор методов. Смотрите также оператор instanceof и объявление типов.
Интерфейсы объектов
Интерфейсы объектов позволяют создавать код, который указывает, какие методы должен реализовать класс, без необходимости описывания их функционала.
Интерфейсы объявляются так же, как и обычные классы, но с использованием ключевого слова interface. Тела методов интерфейсов должны быть пустыми.
Все методы, определенные в интерфейсы должны быть публичными, что следует из самой природы интерфейса.
implements
Для реализации интерфейса используется оператор implements. Класс должен реализовать все методы, описанные в интерфейсе; иначе произойдет фатальная ошибка. При желании классы могут реализовывать более одного интерфейса за раз, реализуемые интерфейсы должны разделяться запятой.
Замечание:
Класс не может реализовать два интерфейса, содержащих одноименную функцию, так как это повлечет за собой неоднозначность.
Замечание:
Интерфейсы могут быть унаследованы друг от друга, так же как и классы, с помощью оператора extends.
Замечание:
Сигнатуры методов в классе, реализующем интерфейс, должны точно совпадать с сигнатурами, используемыми в интерфейсе, в противном случае будет вызвана фатальная ошибка.
Константы (Constants)
Интерфейсы могут содержать константы. Константы интерфейсов работают точно так же, как и константы классов, за исключением того, что они не могут быть перекрыты наследующим классом или интерфейсом.
Примеры
Пример #1 Пример интерфейса
// Объявим интерфейс ‘iTemplate’
interface iTemplate
<
public function setVariable ( $name , $var );
public function getHtml ( $template );
>
// Реализуем интерфейс
// Это сработает нормально
class Template implements iTemplate
<
private $vars = array();
public function setVariable ( $name , $var )
<
$this -> vars [ $name ] = $var ;
>
public function getHtml ( $template )
<
foreach( $this -> vars as $name => $value ) <
$template = str_replace ( ‘<' . $name . '>‘ , $value , $template );
>
// Это не будет работать
// Fatal error: Class BadTemplate contains 1 abstract methods
// and must therefore be declared abstract (iTemplate::getHtml)
// (Фатальная ошибка: Класс BadTemplate содержит 1 абстрактный метод
// и поэтому должнен быть объявлен абстрактным (iTemplate::getHtml))
class BadTemplate implements iTemplate
<
private $vars = array();
public function setVariable ( $name , $var )
<
$this -> vars [ $name ] = $var ;
>
>
?>
Пример #2 Расширяемые интерфейсы
<?php
interface a
<
public function foo ();
>
interface b extends a
<
public function baz ( Baz $baz );
>
// Это сработает
class c implements b
<
public function foo ()
<
>
public function baz ( Baz $baz )
<
>
>
// Это не сработает и выдаст фатальную ошибку
class d implements b
<
public function foo ()
<
>
Пример #3 Множественное наследование интерфейсов
<?php
interface a
<
public function foo ();
>
interface b
<
public function bar ();
>
interface c extends a , b
<
public function baz ();
>
class d implements c
<
public function foo ()
<
>
public function bar ()
<
>
Пример #4 Интерфейсы с константами
<?php
interface a
<
const b = ‘Константа интерфейса’ ;
>
// Выведет: Константа интерфейса
echo a :: b ;
// Вот это, однако, не будет работать, так как
// константы перекрывать нельзя.
class b implements a
<
const b = ‘Class constant’ ;
>
?>
Интерфейс, совместно с контролем типов, предоставляет отличный способ проверки того, что определенный объект содержит определенный набор методов. Смотрите также оператор instanceof и контроль типов.
PHP ООП — Интерфейсы
Интерфейсы позволяют указать, какие методы должен реализовывать класс.
Интерфейсы позволяют легко использовать различные классы одним и тем же способом. Когда один или несколько классов используют один и тот же интерфейс, это называется "полиморфизмом".
Интерфейсы объявляются с помощью ключевого слова interface :
Синтаксис
PHP — Интерфейсы и абстрактные классы
Интерфейс похож на абстрактные классы. Разница между интерфейсами и абстрактными классами заключается в следующем:
- Интерфейсы не могут иметь свойств, в то время как абстрактные классы могут
- Все методы интерфейса должны быть общедоступными, а методы абстрактного класса — общедоступными или защищенными
- Все методы в интерфейсе являются абстрактными, поэтому они не могут быть реализованы в коде, и ключевое слово abstract не требуется
- Классы могут реализовывать интерфейс, одновременно наследуя от другого класса
PHP — Использование интерфейсов
Чтобы реализовать интерфейс, класс должен использовать ключевое слово implements .
Класс, реализующий интерфейс, должен реализовывать все методы интерфейса.
Пример
<?php
interface Animal <
public function makeSound();
>
class Cat implements Animal <
public function makeSound() <
echo "Meow";
>
>
Из приведенного выше примера предположим, что мы хотели бы написать программу, которая управляет группой животных. Есть действия, которые могут выполнять все животные, но каждое животное делает это по-своему.
Используя интерфейсы, мы можем написать код, который может работать для всех животных, даже если каждое животное ведёт себя по-разному:
Пример
<?php
// Определение интерфейса
interface Animal <
public function makeSound();
>
// Определения классов
class Cat implements Animal <
public function makeSound() <
echo " Meow ";
>
>
class Dog implements Animal <
public function makeSound() <
echo " Bark ";
>
>
class Mouse implements Animal <
public function makeSound() <
echo " Squeak ";
>
>
// Составьте список животных
$cat = new Cat();
$dog = new Dog();
$mouse = new Mouse();
$animals = array($cat, $dog, $mouse);
// Скажите животным издать звук
foreach($animals as $animal) <
$animal->makeSound();
>
?>
Объяснение примера
Cat, Dog и Mouse — все классы, реализующие интерфейс Animal, что означает, что все они могут издавать звук с помощью метода makeSound() . Из-за этого мы можем перебрать всех животных и сказать им, чтобы они издали звук, даже если мы не знаем, к какому типу животных относится каждое из них.
Поскольку интерфейс не сообщает классам, как реализовать метод, каждое животное может издавать звук по-своему.
Интерфейсы (ключевое слово `interface`) — PHP: Введение в ООП
Вместе с классами в PHP широко используется языковая конструкция "интерфейс". В этом уроке мы рассмотрим техническую сторону вопроса, а потом поговорим о смысле. Про последнее я сейчас могу сказать немного, потому что полноценный разговор про суть интерфейсов у нас пойдёт во время изучения полиморфизма в последующих курсах. А пока достаточно иметь общее представление об интерфейсах, так как без них не получится окунуться во фреймворки.
Интерфейс в PHP — конструкция языка, описывающая абстрактный тип данных (АТД). Напомню, что АТД определяет набор операций (функций), независимых от конкретной реализации типа (в нашем случае класса) для манипулирования его значениями. На практике интерфейсы содержат определения функций (то есть описание их сигнатур) без их реализации.
Хотя данная конструкция для нас в новинку, само понятие интерфейса используется на протяжении всего курса. В первую очередь это рассуждения о типах. Для оперирования точками на плоскости нам не нужна "реализация" точек. Достаточно того, что мы представляем их визуально и знаем операции, выполняемые над ними. То же самое касается и более базовых концепций, например, чисел и любых арифметических операций. Задумывались ли вы над тем, как на самом деле выполняются арифметические операции? Ответ на этот вопрос гораздо сложнее, чем может показаться на первый взгляд, и он зависит не только от языка, но и от конкретного аппаратного обеспечения (железа). Однако незнание ответа не мешает нам пользоваться числами, строками и массивами, не зная их устройства.
То, что раньше мы описывали словами и держали в голове, теперь явно записано в виде кода. Декартова точка — это АТД с тремя операциями:
- Создание точки из двух значений
- Извлечение координаты X
- Извлечение координаты Y
По сути, прикладному коду больше ничего знать о точках и не нужно. Естественно, если нам понадобятся новые операции, то мы всегда можем их добавить, тем самым расширив интерфейс. Свои собственные АТД можно менять как угодно и когда угодно, только учтите, что изменение интерфейса обычно приводит к необходимости править код, использующий его.
Сама по себе конструкция Interface никак не влияет на остальной код. Недостаточно просто создать интерфейс, в этом нет смысла. Интерфейс должен быть реализован, и тогда он начнёт приносить пользу.
Реализация интерфейса происходит за счёт ключевого слова implements , за которым идёт название интерфейса. Интерпретатор проверяет, чтобы в классе были описаны все функции интерфейса и их сигнатуры совпадали, а если это не так, то возникает ошибка. Реализация интерфейса никак не ограничивает возможности по наполнению класса, другими словами, вы можете определять и добавлять в класс все, что хотите, помимо интерфейсных функций.
Насколько наличие интерфейсов критично для PHP программ? Например, можно в любой программе открыть все файлы с классами и удалить часть определения класса, которая описывает реализацию интерфейсов (слово implements и то, что идёт за ним). После этого не изменится ровным счётом ничего — программа продолжит выполняться так же, как и выполнялась. Но ситуация меняется, если использовать интерфейс в сигнатурах функций и методов вместо классов.
Во время выполнения программы PHP проверяет, реализует ли класс соответствующий интерфейс, и если нет, то возникает ошибка. Причём проверка идёт именно на наличие записи implements в определении класса, а не на факт того, что методы определены (проверка реализации интерфейса гарантирует это).
Такая запись позволяет коду завязываться не на конкретную реализацию точек, а на их интерфейс. Это — ключевая мысль, которую имеет смысл обсуждать подробнее вместе с полиморфизмом.
Отдельно стоит сказать, что один класс может реализовывать любое число интерфейсов, в таком случае они описываются через запятую:
Здесь класс Stack реализует сразу три интерфейса. Это значит, что внутри него должны быть реализованы методы всех указанных интерфейсов.
Если у разных интерфейсов окажутся методы с одинаковым названием, но разной сигнатурой, то возникнет ошибка. В таком случае придётся отказаться от одного из интерфейсов либо переделать их (например, переименовать методы)
Интерфейс Countable
В PHP встроен интерфейс Countable, а функция count умеет работать с любым объектом, реализующим этот интерфейс.