1
0
mirror of https://github.com/php/doc-ru.git synced 2026-03-26 16:52:12 +01:00
Files
archived-doc-ru/language/oop5/interfaces.xml
2023-09-03 01:02:10 +03:00

374 lines
13 KiB
XML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?xml version="1.0" encoding="utf-8"?>
<!-- EN-Revision: 3d522c890d98c563bb283cf89ec5da5f535cfb8f Maintainer: shein Status: ready -->
<!-- Reviewed: no -->
<sect1 xml:id="language.oop5.interfaces" xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>Интерфейсы объектов</title>
<para>
Интерфейсы объектов позволяют создавать код, который
указывает, какие методы должен реализовать класс, без
необходимости определять, как именно они должны быть реализованы.
Интерфейсы разделяют пространство имён с классами и трейтами,
поэтому они не могут называться одинаково.
</para>
<para>
Интерфейсы объявляются так же, как и обычные классы, но с использованием
ключевого слова <literal>interface</literal> вместо <literal>class</literal>.
Тела методов интерфейсов должны быть пустыми.
</para>
<para>
Все методы, определённые в интерфейсах, должны быть общедоступными, что
следует из самой природы интерфейса.
</para>
<para>
На практике интерфейсы используются в двух взаимодополняющих случаях:
</para>
<simplelist>
<member>
Чтобы позволить разработчикам создавать объекты разных классов, которые могут использоваться взаимозаменяемо,
поскольку они реализуют один и тот же интерфейс или интерфейсы.
Типичный пример - несколько служб доступа к базе данных, несколько платёжных шлюзов или разных стратегий кеширования.
Различные реализации могут быть заменены без каких-либо изменений в коде, который их использует.
</member>
<member>
Чтобы разрешить функции или методу принимать и оперировать параметром, который соответствует
интерфейсу, не заботясь о том, что ещё может делать объект или как он реализован.
Эти интерфейсы часто называют <literal>Iterable</literal>, <literal>Cacheable</literal>, <literal>Renderable</literal>
и так далее, чтобы описать их поведение.
</member>
</simplelist>
<para>
Интерфейсы могут определять
<link linkend="language.oop5.magic">магические методы</link>, требуя от реализующих классов реализации этих методов.
</para>
<note>
<para>
Хотя они поддерживаются, использование <link linkend="language.oop5.decon.constructor">конструкторов</link>
в интерфейсах настоятельно не рекомендуется. Это значительно снижает гибкость объекта, реализующего интерфейс.
Кроме того, к конструкторам не применяются правила наследования, что может привести к противоречивому
и неожиданному поведению.
</para>
</note>
<sect2 xml:id="language.oop5.interfaces.implements">
<title><literal>implements</literal></title>
<para>
Для реализации интерфейса используется оператор <literal>implements</literal>.
Класс должен реализовать все методы, описанные в интерфейсе, иначе
произойдёт фатальная ошибка. При желании классы могут реализовывать
более одного интерфейса, разделяя каждый интерфейс запятой.
</para>
<warning>
<para>
Класс, реализующий интерфейс, может использовать для своих параметров имя, отличное
от имени интерфейса. Однако, начиная с PHP 8.0, в языке поддерживаются
<link linkend="functions.named-arguments">именованные аргументы</link>, и вызывающий код может полагаться на имя параметра в интерфейсе.
По этой причине настоятельно рекомендуется, чтобы разработчики использовали те же имена параметров, что и реализуемый интерфейс.
</para>
</warning>
<note>
<para>
Интерфейсы могут быть унаследованы друг от друга, так же, как и классы,
с помощью оператора <link linkend="language.oop5.inheritance">extends</link>.
</para>
</note>
<note>
<para>
Класс, реализующий интерфейс, должен объявить все методы в интерфейсе с
<link linkend="language.oop.lsp">совместимой сигнатурой</link>. Класс может
реализовывать несколько интерфейсов, которые объявляют метод с одинаковым именем.
В этом случае реализация должна следовать <link linkend="language.oop.lsp">правилам совместимости сигнатуры</link>
для всех интерфейсов. Таким образом, можно применять <link linkend="language.oop5.variance">ковариантность и контравариантность</link>.
</para>
</note>
</sect2>
<!-- Move this to OOP constants page? -->
<sect2 xml:id="language.oop5.interfaces.constants">
<title>Константы</title>
<para>
Интерфейсы могут содержать константы. Константы интерфейсов
работают точно так же, как и <link linkend="language.oop5.constants">константы классов</link>.
До PHP 8.1.0 они не могли быть переопределены классом или интерфейсом, который их наследует.
</para>
</sect2>
<sect2 xml:id="language.oop5.interfaces.examples">
&reftitle.examples;
<example xml:id="language.oop5.interfaces.examples.ex1">
<title>Пример интерфейса</title>
<programlisting role="php">
<![CDATA[
<?php
// Объявим интерфейс '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);
}
return $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;
}
}
?>
]]>
</programlisting>
</example>
<example xml:id="language.oop5.interfaces.examples.ex2">
<title>Наследование интерфейсов</title>
<programlisting role="php">
<![CDATA[
<?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()
{
}
public function baz(Foo $foo)
{
}
}
?>
]]>
</programlisting>
</example>
<example xml:id="language.oop5.interfaces.examples.variance.multiple.interfaces">
<title>Совместимость с несколькими интерфейсами</title>
<programlisting role="php">
<![CDATA[
<?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();
}
}
?>
]]>
</programlisting>
</example>
<example xml:id="language.oop5.interfaces.examples.ex3">
<title>Множественное наследование интерфейсов</title>
<programlisting role="php">
<![CDATA[
<?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()
{
}
}
?>
]]>
</programlisting>
</example>
<example xml:id="language.oop5.interfaces.examples.ex4">
<title>Интерфейсы с константами</title>
<programlisting role="php">
<![CDATA[
<?php
interface A
{
const B = 'Константа интерфейса';
}
// Выведет: Константа интерфейса
echo A::B;
class B implements A
{
const B = 'Константа класса';
}
// Выведет: Константа класса
// До PHP 8.1.0 этот код не будет работать,
// потому что было нельзя переопределять константы.
echo B::B;
?>
]]>
</programlisting>
</example>
<example xml:id="language.oop5.interfaces.examples.ex5">
<title>Интерфейсы с абстрактными классами</title>
<programlisting role="php">
<![CDATA[
<?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;
}
}
?>
]]>
</programlisting>
</example>
<example xml:id="language.oop5.interfaces.examples.ex6">
<title>Одновременное расширение и внедрение</title>
<programlisting role="php">
<![CDATA[
<?php
class One
{
/* ... */
}
interface Usable
{
/* ... */
}
interface Updatable
{
/* ... */
}
// Порядок ключевых слов здесь важен. "extends" должно быть первым.
class Two extends One implements Usable, Updatable
{
/* ... */
}
?>
]]>
</programlisting>
</example>
<para>
Интерфейс, совместно с объявлениями типов, предоставляет отличный
способ проверки того, что определённый объект содержит определённый
набор методов. Смотрите также оператор
<link linkend="language.operators.type">instanceof</link> и
<link linkend="language.types.declarations">объявление типов</link>.
</para>
</sect2>
</sect1><!-- Keep this comment at the end of the file
Local variables:
mode: sgml
sgml-omittag:t
sgml-shorttag:t
sgml-minimize-attributes:nil
sgml-always-quote-attributes:t
sgml-indent-step:1
sgml-indent-data:t
indent-tabs-mode:nil
sgml-parent-document:nil
sgml-default-dtd-file:"~/.phpdoc/manual.ced"
sgml-exposed-tags:nil
sgml-local-catalogs:nil
sgml-local-ecat-files:nil
End:
vim600: syn=xml fen fdm=syntax fdl=2 si
vim: et tw=78 syn=sgml
vi: ts=1 sw=1
-->