Php что такое интерфейс
Перейти к содержимому

Php что такое интерфейс

  • автор:

Интерфейсы в ООП на PHP

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

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

Фактически ваш родительский класс описывает потомков, то есть набор их публичных методов, обязательных для реализации.

Зачем нам такое нужно: чтобы при программировании совершать меньше ошибок — описав все необходимые методы в классе-родителе, мы можем быть уверенны в том, что все потомки их действительно реализуют.

Когда это поможет: пусть мы создадим наш класс-родитель и несколько потомков к нему. Если потом через некоторое время, например, через месяц, мы решим создать еще одного потомка, наверняка мы уже забудем детали нашего кода и вполне можем забыть написать реализацию какого-нибудь метода в новом потомке. Однако сам PHP не позволит потерять метод — и просто выдаст ошибку.

То же самое касается другого программиста, работающего с вашим проектом. Пусть код класса-родителя писали вы, а затем ваш коллега решил создать еще одного потомка. У вашего коллеги также не получится потерять парочку методов.

Есть, однако, проблема: фактически мы сделали наш класс-родитель для того, чтобы писать в нем абстрактные публичные методы, но мы сами или наш коллега имеем возможность случайно добавить в этот класс не публичный метод или не абстрактный.

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

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

Интерфейсы объявляются так же, как и обычные классы, но используя ключевое слово interface вместо слова class .

Для наследования от интерфейсов используется немного другая терминология: говорят, что классы не наследуют от интерфейсов, а их. Соответственно вместо слова extends следует использовать ключевое слово implements .

Нельзя создать объект интерфейса. Все методы интерфейса должны быть объявлены как public и не должны иметь реализации. У интерфейса могут быть только методы, но не свойства. Нельзя также сделать интерфейс и класс с одним и тем же названием.

Попробуем на практике

Давайте попробуем на практике. Решим задачу на фигуры из предыдущего рока, но уже используя интерфейсы, а не абстрактные классы.

Итак, теперь у нас дан интерфейс Figure :

Давайте напишем класс Quadrate , который будет реализовывать методы этого интерфейса:

a = $a; > public function getSquare() < return $this->a * $this->a; > public function getPerimeter() < return 4 * $this->a; > > ?>

Как это работает: если забыть реализовать какой-нибудь метод, описанный в интерфейсе, PHP выдаст нам фатальную ошибку. Давайте реализуем также класс Rectangle :

Сделайте класс Disk ( круг ), реализующий интерфейс Figure .

Замечание

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

Общепринято в таком случае название интерфейса начать с маленькой буквы i , чтобы показать, что это интерфейс, а не класс. То есть в нашем случае мы сделаем интерфейс iUser , а реализовывать его будет класс User . Такой подход мы иногда будем применять в следующих уроках.

Php что такое интерфейс

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

Интерфейсы объявляются так же, как и обычные классы, но с использованием ключевого слова interface вместо class . Тела методов интерфейсов должны быть пустыми.

Все методы, определённые в интерфейсах, должны быть общедоступными, что следует из самой природы интерфейса.

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

  • Чтобы позволить разработчикам создавать объекты разных классов, которые могут использоваться взаимозаменяемо, поскольку они реализуют один и тот же интерфейс или интерфейсы. Типичный пример — несколько служб доступа к базе данных, несколько платёжных шлюзов или разных стратегий кеширования. Различные реализации могут быть заменены без каких-либо изменений в коде, который их использует.
  • Чтобы разрешить функции или методу принимать и оперировать параметром, который соответствует интерфейсу, не заботясь о том, что ещё может делать объект или как он реализован. Эти интерфейсы часто называют Iterable , Cacheable , Renderable и так далее, чтобы описать их поведение.

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

Замечание:

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

implements

Для реализации интерфейса используется оператор implements . Класс должен реализовать все методы, описанные в интерфейсе, иначе произойдёт фатальная ошибка. При желании классы могут реализовывать более одного интерфейса, разделяя каждый интерфейс запятой.

Внимание

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

Замечание:

Интерфейсы могут быть унаследованы друг от друга, так же, как и классы, с помощью оператора extends.

Замечание:

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

Константы

Интерфейсы могут содержать константы. Константы интерфейсов работают точно так же, как и константы классов. До 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 ( » , $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 Наследование интерфейсов

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 Совместимость с несколькими интерфейсами

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 Множественное наследование интерфейсов

interface B
public function bar ();
>

interface C extends A , B
public function baz ();
>

class D implements C
public function foo ()
>

public function bar ()
>

Пример #5 Интерфейсы с константами

interface A
const B = ‘Константа интерфейса’ ;
>

// Выведет: Константа интерфейса
echo A :: B ;

class B implements A
const B = ‘Константа класса’ ;
>

// Выведет: Константа класса
// До PHP 8.1.0 этот код не будет работать,
// потому что было нельзя переопределять константы.
echo B :: B ;
?>

Пример #6 Интерфейсы с абстрактными классами

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 ( » , $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 Расширяемые интерфейсы

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 Множественное наследование интерфейсов

interface b
public function bar ();
>

interface c extends a , b
public function baz ();
>

class d implements c
public function foo ()
>

public function bar ()
>

Пример #4 Интерфейсы с константами

interface a
const b = ‘Константа интерфейса’ ;
>

// Выведет: Константа интерфейса
echo a :: b ;

// Вот это, однако, не будет работать, так как
// константы перекрывать нельзя.
class b implements a
const b = ‘Class constant’ ;
>
?>

Интерфейс, совместно с контролем типов, предоставляет отличный способ проверки того, что определенный объект содержит определенный набор методов. Смотрите также оператор instanceof и контроль типов.

Php что такое интерфейс

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

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

interface Messenger <>

Здесь определен интерфейс Messenger . Внутри блока интерфейса в фигурных скобках определяются сигнатуры методов. Причем все эти методы могут быть только публичными, то есть с модификатором public , либо без модификатора доступа (что аналоично модификатору public):

interface Messenger

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

Для реализации классом интерфейса применяется ключевое слово implements , после которого указывается имя применяемого интерфейса:

 class EmailMessenger implements Messenger < function send() < echo "Отправка сообщения на e-mail"; >> $outlook = new EmailMessenger(); $outlook->send(); ?>

В данном случае класс EmailMessenger реализует интерфейс Messenger. Если класс применяет интерфейс, то он должен реализовать все методы этого интерфейса. Так, в данном случае класс EmailMessenger определяет метод send() с некоторой реализацией.

Интерфейсы также могут наследоваться от других интерфейсов:

 interface EmailMessenger extends Messenger < >class SimpleEmailMessenger implements EmailMessenger < function send() < echo "Отправка сообщения на email."; >> $outlook = new SimpleEmailMessenger(); $outlook->send(); ?>

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

 function sendMessage(Messenger $messenger, $text) < $messenger->send($text); > class EmailMessenger implements Messenger < function send($message) < echo "Отправка сообщения на email: $message"; >> $outlook = new EmailMessenger(); sendMessage($outlook, "Hello World"); ?>

Для отправки сообщения здесь определена функция sendMessage() , которая в качестве первого параметра принимает объект мессандера, а в качестве второго параметра — отправляемый текст. Причем определение первого параметра говорит, что передаваемое этому параметру значение должно реализовать интерфейс Messenger. В самой функции мы знаем, что первый параметр — это объект, который обязательно реализует интерфейс Messenger, поэтому мы можем вызвать у него метод send() для отправки сообщения:

function sendMessage(Messenger $messenger, $text) < $messenger->send($text); >

Множественное применение интерфейсов

Класс может одновременно применять сразу несколько интерфейсов. В этом случае все интерфейсы перечисляются через запятую после слова implements . А класс должен реализовать методы всех применяемых интерфейсов:

interface Camera < function makeVideo(); function makePhoto(); >interface Messenger < function sendMessage($message); >class Mobile implements Camera, Messenger < function makeVideo()< echo "Запись видео";>function makePhoto() < echo "Съемка фото";>function sendMessage($message) > $iphone12 = new Mobile(); $iphone12->makePhoto();

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *