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

Интерфейсы определяются так же, как и классы, но с 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
{
    /* ... */
}
?>

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