Интерфейсы объектов позволяют вам создавать код, определяющий, какие методы должен реализовать класс, без необходимости определять, как эти методы реализованы. Интерфейсы имеют общее пространство имен с классами и трейтами, поэтому они не могут использовать одно и то же имя.
Интерфейсы определяются так же, как и классы, но с interface
заменой class
ключевого слова ключевым словом и без определения содержания каких-либо методов.
Все методы, объявленные в интерфейсе, должны быть общедоступными; это природа интерфейса.
На практике интерфейсы служат двум взаимодополняющим целям:
- Чтобы позволить разработчикам создавать объекты разных классов, которые могут использоваться взаимозаменяемо, поскольку они реализуют один и тот же интерфейс или интерфейсы. Типичным примером является несколько служб доступа к базе данных, несколько платежных шлюзов или разные стратегии кэширования. Различные реализации могут быть заменены без каких-либо изменений в коде, который их использует.
- Разрешить функции или методу принимать параметр, соответствующий интерфейсу, и работать с ним, не заботясь о том, что еще может делать объект или как он реализован. Эти интерфейсы часто называют
Iterable
,Cacheable
,Renderable
, или так далее, чтобы описать значение поведения.
Интерфейсы могут определять магические методы , требующие реализации классов для реализации этих методов.
Примечание :
Хотя они и поддерживаются, включение конструкторов в интерфейсы настоятельно не рекомендуется. Это значительно снижает гибкость объекта, реализующего интерфейс. Кроме того, конструкторы не подчиняются правилам наследования, что может привести к несогласованному и неожиданному поведению.
implements
Для реализации интерфейса используется implements
оператор. Все методы интерфейса должны быть реализованы внутри класса; невыполнение этого требования приведет к фатальной ошибке. При желании классы могут реализовывать более одного интерфейса, разделяя каждый интерфейс запятой.
Предупреждение
Класс может реализовать два интерфейса, которые определяют метод с одинаковым именем, только если объявление метода в обоих интерфейсах идентично.
Предупреждение
Класс, реализующий интерфейс, может использовать имя для своих параметров, отличное от имени интерфейса. Однако, начиная с PHP 8.0, язык поддерживает именованные аргументы , что означает, что вызывающие объекты могут полагаться на имя параметра в интерфейсе. По этой причине настоятельно рекомендуется, чтобы разработчики использовали те же имена параметров, что и реализуемый интерфейс.
Примечание :
Интерфейсы могут быть расширены как классы с помощью оператора extends .
Примечание :
Класс, реализующий интерфейс, должен объявить все методы интерфейса с совместимой сигнатурой .
Constants
Интерфейсы могут иметь константы. Константы интерфейса работают точно так же, как константы класса . До PHP 8.1.0 они не могут быть переопределены классом/интерфейсом, который их наследует.
Примеры
Пример #1 Пример интерфейса
<?php
// Declare the interface 'Template'
interface Template
{
public function setVariable($name, $var);
public function getHtml($template);
}
// Implement the interface
// This will work
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);
}
return $template;
}
}
// This will not work
// Fatal error: Class BadTemplate contains 1 abstract methods
// and must therefore be declared abstract (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);
}
// This will work
class C implements B
{
public function foo()
{
}
public function baz(Baz $baz)
{
}
}
// This will not work and result in a fatal error
class D implements B
{
public function foo()
{
}
public function baz(Foo $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()
{
}
public function baz()
{
}
}
?>
Пример #4 Интерфейсы с константами
<?php
interface A
{
const B = 'Interface constant';
}
// Prints: Interface constant
echo A::B;
class B implements A
{
const B = 'Class constant';
}
// Prints: Class constant
// Prior to PHP 8.1.0, this will however not work because it was not
// allowed to override constants.
echo B::B;
?>
Пример #5 Интерфейсы с абстрактными классами
<?php
interface A
{
public function foo(string $s): string;
public function bar(int $i): int;
}
// An abstract class may implement only a portion of an interface.
// Classes that extend the abstract class must implement the rest.
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;
}
}
?>
Пример #6 Расширение и реализация одновременно
<?php
class One
{
/* ... */
}
interface Usable
{
/* ... */
}
interface Updatable
{
/* ... */
}
// The keyword order here is important. 'extends' must come first.
class Two extends One implements Usable, Updatable
{
/* ... */
}
?>
Интерфейс вместе с объявлениями типов обеспечивает хороший способ убедиться, что конкретный объект содержит определенные методы.
0 комментариев