language/oop5/interfaces.xml
3d522c890d98c563bb283cf89ec5da5f535cfb8f
...
...
@@ -1,14 +1,15 @@
1
1
<?xml version="1.0" encoding="utf-8"?>
2
2
<!-- $Revision$ -->
3
-
<sect1 xml:id="language.oop5.interfaces" xmlns="http://docbook.org/ns/docbook">
3
+
<sect1 xml:id="language.oop5.interfaces" xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink">
4
4
<title>Object Interfaces</title>
5
5
<para>
6
6
Object interfaces allow you to create code which specifies which methods a
7
7
class must implement, without having to define how these methods are
8
-
handled.
8
+
implemented. Interfaces share a namespace with classes and traits, so they may
9
+
not use the same name.
9
10
</para>
10
11
<para>
11
-
Interfaces are defined in the same was as a class, but with the <literal>interface</literal>
12
+
Interfaces are defined in the same way as a class, but with the <literal>interface</literal>
12
13
keyword replacing the <literal>class</literal> keyword and without any of the methods having
13
14
their contents defined.
14
15
</para>
...
...
@@ -16,6 +17,37 @@
16
17
All methods declared in an interface must be public; this is the nature of an
17
18
interface.
18
19
</para>
20
+
<para>
21
+
In practice, interfaces serve two complementary purposes:
22
+
</para>
23
+
<simplelist>
24
+
<member>
25
+
To allow developers to create objects of different classes that may be used interchangeably
26
+
because they implement the same interface or interfaces. A common example is multiple database access services,
27
+
multiple payment gateways, or different caching strategies. Different implementations may
28
+
be swapped out without requiring any changes to the code that uses them.
29
+
</member>
30
+
<member>
31
+
To allow a function or method to accept and operate on a parameter that conforms to an
32
+
interface, while not caring what else the object may do or how it is implemented. These interfaces
33
+
are often named like <literal>Iterable</literal>, <literal>Cacheable</literal>, <literal>Renderable</literal>,
34
+
or so on to describe the significance of the behavior.
35
+
</member>
36
+
</simplelist>
37
+
<para>
38
+
Interfaces may define
39
+
<link linkend="language.oop5.magic">magic methods</link> to require implementing classes to
40
+
implement those methods.
41
+
</para>
42
+
<note>
43
+
<para>
44
+
Although they are supported, including <link linkend="language.oop5.decon.constructor">constructors</link>
45
+
in interfaces is strongly discouraged. Doing so significantly reduces the flexibility of the object implementing the
46
+
interface. Additionally, constructors are not enforced by inheritance rules, which can cause inconsistent
47
+
and unexpected behavior.
48
+
</para>
49
+
</note>
50
+

19
51
<sect2 xml:id="language.oop5.interfaces.implements">
20
52
<title><literal>implements</literal></title>
21
53
<para>
...
...
@@ -24,14 +56,14 @@
24
56
so will result in a fatal error. Classes may implement more than one interface
25
57
if desired by separating each interface with a comma.
26
58
</para>
27
-
<note>
59
+
<warning>
28
60
<para>
29
-
Prior to PHP 5.3.9, a class could not implement two interfaces that
30
-
specified a method with the same name, since it would cause ambiguity.
31
-
More recent versions of PHP allow this as long as the duplicate methods
32
-
have the same signature.
61
+
A class that implements an interface may use a different name for its parameters than
62
+
the interface. However, as of PHP 8.0 the language supports <link linkend="functions.named-arguments">named arguments</link>, which means
63
+
callers may rely on the parameter name in the interface. For that reason, it is strongly
64
+
recommended that developers use the same parameter names as the interface being implemented.
33
65
</para>
34
-
</note>
66
+
</warning>
35
67
<note>
36
68
<para>
37
69
Interfaces can be extended like classes using the <link linkend="language.oop5.inheritance">extends</link>
...
...
@@ -40,18 +72,21 @@
40
72
</note>
41
73
<note>
42
74
<para>
43
-
The class implementing the interface must use the exact same method
44
-
signatures as are defined in the interface. Not doing so will result in a
45
-
fatal error.
46
-
</para>
47
-
</note>
75
+
The class implementing the interface must declare all methods in the interface
76
+
with a <link linkend="language.oop.lsp">compatible signature</link>. A class can implement multiple interfaces
77
+
which declare a method with the same name. In this case, the implementation must follow the
78
+
<link linkend="language.oop.lsp">signature compatibility rules</link> for all the interfaces. So
79
+
<link linkend="language.oop5.variance">covariance and contravariance</link> can be applied.
80
+
</para>
81
+
</note>
48
82
</sect2>
83
+
<!-- Move this to OOP constants page? -->
49
84
<sect2 xml:id="language.oop5.interfaces.constants">
50
-
<title><literal>Constants</literal></title>
85
+
<title>Constants</title>
51
86
<para>
52
-
It's possible for interfaces to have constants. Interface constants works exactly
53
-
like <link linkend="language.oop5.constants">class constants</link> except
54
-
they cannot be overridden by a class/interface that inherits them.
87
+
It's possible for interfaces to have constants. Interface constants work exactly
88
+
like <link linkend="language.oop5.constants">class constants</link>.
89
+
Prior to PHP 8.1.0, they cannot be overridden by a class/interface that inherits them.
55
90
</para>
56
91
</sect2>
57
92
<sect2 xml:id="language.oop5.interfaces.examples">
...
...
@@ -62,8 +97,8 @@
62
97
<![CDATA[
63
98
<?php
64
99

65
-
// Declare the interface 'iTemplate'
66
-
interface iTemplate
100
+
// Declare the interface 'Template'
101
+
interface Template
67
102
{
68
103
public function setVariable($name, $var);
69
104
public function getHtml($template);
...
...
@@ -71,9 +106,9 @@ interface iTemplate
71
106

72
107
// Implement the interface
73
108
// This will work
74
-
class Template implements iTemplate
109
+
class WorkingTemplate implements Template
75
110
{
76
-
private $vars = array();
111
+
private $vars = [];
77
112
78
113
public function setVariable($name, $var)
79
114
{
...
...
@@ -92,10 +127,10 @@ class Template implements iTemplate
92
127

93
128
// This will not work
94
129
// Fatal error: Class BadTemplate contains 1 abstract methods
95
-
// and must therefore be declared abstract (iTemplate::getHtml)
96
-
class BadTemplate implements iTemplate
130
+
// and must therefore be declared abstract (Template::getHtml)
131
+
class BadTemplate implements Template
97
132
{
98
-
private $vars = array();
133
+
private $vars = [];
99
134
100
135
public function setVariable($name, $var)
101
136
{
...
...
@@ -111,18 +146,18 @@ class BadTemplate implements iTemplate
111
146
<programlisting role="php">
112
147
<![CDATA[
113
148
<?php
114
-
interface a
149
+
interface A
115
150
{
116
151
public function foo();
117
152
}
118
153

119
-
interface b extends a
154
+
interface B extends A
120
155
{
121
156
public function baz(Baz $baz);
122
157
}
123
158

124
159
// This will work
125
-
class c implements b
160
+
class C implements B
126
161
{
127
162
public function foo()
128
163
{
...
...
@@ -134,7 +169,7 @@ class c implements b
134
169
}
135
170

136
171
// This will not work and result in a fatal error
137
-
class d implements b
172
+
class D implements B
138
173
{
139
174
public function foo()
140
175
{
...
...
@@ -148,27 +183,54 @@ class d implements b
148
183
]]>
149
184
</programlisting>
150
185
</example>
186
+
<example xml:id="language.oop5.interfaces.examples.variance.multiple.interfaces">
187
+
<title>Variance compatibility with multiple interfaces</title>
188
+
<programlisting role="php">
189
+
<![CDATA[
190
+
<?php
191
+
class Foo {}
192
+
class Bar extends Foo {}
193
+

194
+
interface A {
195
+
public function myfunc(Foo $arg): Foo;
196
+
}
197
+

198
+
interface B {
199
+
public function myfunc(Bar $arg): Bar;
200
+
}
201
+

202
+
class MyClass implements A, B
203
+
{
204
+
public function myfunc(Foo $arg): Bar
205
+
{
206
+
return new Bar();
207
+
}
208
+
}
209
+
?>
210
+
]]>
211
+
</programlisting>
212
+
</example>
151
213
<example xml:id="language.oop5.interfaces.examples.ex3">
152
214
<title>Multiple interface inheritance</title>
153
215
<programlisting role="php">
154
216
<![CDATA[
155
217
<?php
156
-
interface a
218
+
interface A
157
219
{
158
220
public function foo();
159
221
}
160
222

161
-
interface b
223
+
interface B
162
224
{
163
225
public function bar();
164
226
}
165
227

166
-
interface c extends a, b
228
+
interface C extends A, B
167
229
{
168
230
public function baz();
169
231
}
170
232

171
-
class d implements c
233
+
class D implements C
172
234
{
173
235
public function foo()
174
236
{
...
...
@@ -191,30 +253,96 @@ class d implements c
191
253
<programlisting role="php">
192
254
<![CDATA[
193
255
<?php
194
-
interface a
256
+
interface A
195
257
{
196
-
const b = 'Interface constant';
258
+
const B = 'Interface constant';
197
259
}
198
260

199
261
// Prints: Interface constant
200
-
echo a::b;
262
+
echo A::B;
263
+

264
+

265
+
class B implements A
266
+
{
267
+
const B = 'Class constant';
268
+
}
201
269

270
+
// Prints: Class constant
271
+
// Prior to PHP 8.1.0, this will however not work because it was not
272
+
// allowed to override constants.
273
+
echo B::B;
274
+
?>
275
+
]]>
276
+
</programlisting>
277
+
</example>
278
+
<example xml:id="language.oop5.interfaces.examples.ex5">
279
+
<title>Interfaces with abstract classes</title>
280
+
<programlisting role="php">
281
+
<![CDATA[
282
+
<?php
283
+
interface A
284
+
{
285
+
public function foo(string $s): string;
286
+

287
+
public function bar(int $i): int;
288
+
}
289
+

290
+
// An abstract class may implement only a portion of an interface.
291
+
// Classes that extend the abstract class must implement the rest.
292
+
abstract class B implements A
293
+
{
294
+
public function foo(string $s): string
295
+
{
296
+
return $s . PHP_EOL;
297
+
}
298
+
}
299
+

300
+
class C extends B
301
+
{
302
+
public function bar(int $i): int
303
+
{
304
+
return $i * 2;
305
+
}
306
+
}
307
+
?>
308
+
]]>
309
+
</programlisting>
310
+
</example>
311
+
<example xml:id="language.oop5.interfaces.examples.ex6">
312
+
<title>Extending and implementing simultaneously</title>
313
+
<programlisting role="php">
314
+
<![CDATA[
315
+
<?php
316
+

317
+
class One
318
+
{
319
+
/* ... */
320
+
}
321
+

322
+
interface Usable
323
+
{
324
+
/* ... */
325
+
}
326
+

327
+
interface Updatable
328
+
{
329
+
/* ... */
330
+
}
202
331

203
-
// This will however not work because it's not allowed to
204
-
// override constants.
205
-
class b implements a
332
+
// The keyword order here is important. 'extends' must come first.
333
+
class Two extends One implements Usable, Updatable
206
334
{
207
-
const b = 'Class constant';
335
+
/* ... */
208
336
}
209
337
?>
210
338
]]>
211
339
</programlisting>
212
340
</example>
213
341
<para>
214
-
An interface, together with type-hinting, provides a good way to make sure
342
+
An interface, together with type declarations, provides a good way to make sure
215
343
that a particular object contains particular methods. See
216
344
<link linkend="language.operators.type">instanceof</link> operator and
217
-
<link linkend="language.oop5.typehinting">type hinting</link>.
345
+
<link linkend="language.types.declarations">type declarations</link>.
218
346
</para>
219
347
</sect2>
220
348

221
349