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
- implemented.
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
12
Interfaces are defined in the same way as a class, but with the <literal >interface</literal >
16
17
All methods declared in an interface must be public; this is the nature of an
17
18
interface.
18
19
</para >
19
-
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 >
20
42
<note >
21
43
<para >
22
- It is possible to declare
23
- <link linkend =" language.oop5.magic" >magic methods</link > such as the
24
- <link linkend =" language.oop5.decon.constructor" >constructor</link >
25
- in an interface, which can be useful in some contexts,
26
- e.g. for use by factories.
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.
27
48
</para >
28
49
</note >
29
50
41
62
same name, only if the method declaration in both interfaces is identical.
42
63
</para >
43
64
</warning >
65
+ <warning >
66
+ <para >
67
+ A class that implements an interface may use a different name for its parameters than
68
+ the interface. However, as of PHP 8.0 the language supports named arguments, which means
69
+ callers may rely on the parameter name in the interface. For that reason, it is strongly
70
+ recommended that developers use the same parameter names as the interface being implemented.
71
+ </para >
72
+ </warning >
44
73
<note >
45
74
<para >
46
75
Interfaces can be extended like classes using the <link linkend =" language.oop5.inheritance" >extends</link >
49
78
</note >
50
79
<note >
51
80
<para >
52
- The class implementing the interface must declare a method which has a
53
- <link linkend =" language.oop.lsp" >compatible signature</link >.
81
+ The class implementing the interface must declare all methods in the interface
82
+ with a <link linkend =" language.oop.lsp" >compatible signature</link >.
54
83
</para >
55
84
</note >
56
85
</sect2 >
71
100
<![CDATA[
72
101
<?php
73
102
74
- // Declare the interface 'iTemplate '
75
- interface iTemplate
103
+ // Declare the interface 'Template '
104
+ interface Template
76
105
{
77
106
public function setVariable($name, $var);
78
107
public function getHtml($template);
79
108
}
80
109
81
110
// Implement the interface
82
111
// This will work
83
- class Template implements iTemplate
112
+ class WorkingTemplate implements Template
84
113
{
85
- private $vars = array() ;
114
+ private $vars = [] ;
86
115
87
116
public function setVariable($name, $var)
88
117
{
@@ -101,10 +130,10 @@ class Template implements iTemplate
101
130
102
131
// This will not work
103
132
// Fatal error: Class BadTemplate contains 1 abstract methods
104
- // and must therefore be declared abstract (iTemplate ::getHtml)
105
- class BadTemplate implements iTemplate
133
+ // and must therefore be declared abstract (Template ::getHtml)
134
+ class BadTemplate implements Template
106
135
{
107
- private $vars = array() ;
136
+ private $vars = [] ;
108
137
109
138
public function setVariable($name, $var)
110
139
{
@@ -120,18 +149,18 @@ class BadTemplate implements iTemplate
120
149
<programlisting role =" php" >
121
150
<![CDATA[
122
151
<?php
123
- interface a
152
+ interface A
124
153
{
125
154
public function foo();
126
155
}
127
156
128
- interface b extends a
157
+ interface B extends A
129
158
{
130
159
public function baz(Baz $baz);
131
160
}
132
161
133
162
// This will work
134
- class c implements b
163
+ class C implements B
135
164
{
136
165
public function foo()
137
166
{
@@ -143,7 +172,7 @@ class c implements b
143
172
}
144
173
145
174
// This will not work and result in a fatal error
146
- class d implements b
175
+ class D implements B
147
176
{
148
177
public function foo()
149
178
{
@@ -162,22 +191,22 @@ class d implements b
162
191
<programlisting role =" php" >
163
192
<![CDATA[
164
193
<?php
165
- interface a
194
+ interface A
166
195
{
167
196
public function foo();
168
197
}
169
198
170
- interface b
199
+ interface B
171
200
{
172
201
public function bar();
173
202
}
174
203
175
- interface c extends a, b
204
+ interface C extends A, B
176
205
{
177
206
public function baz();
178
207
}
179
208
180
- class d implements c
209
+ class D implements C
181
210
{
182
211
public function foo()
183
212
{
@@ -200,20 +229,83 @@ class d implements c
200
229
<programlisting role =" php" >
201
230
<![CDATA[
202
231
<?php
203
- interface a
232
+ interface A
204
233
{
205
- const b = 'Interface constant';
234
+ const B = 'Interface constant';
206
235
}
207
236
208
237
// Prints: Interface constant
209
- echo a::b ;
238
+ echo A::B ;
210
239
211
240
212
241
// This will however not work because it's not allowed to
213
242
// override constants.
214
- class b implements a
243
+ class B implements A
244
+ {
245
+ const B = 'Class constant';
246
+ }
247
+ ?>
248
+ ]]>
249
+ </programlisting >
250
+ </example >
251
+ <example xml : id =" language.oop5.interfaces.examples.ex5" >
252
+ <title >Interfaces with abstract classes</title >
253
+ <programlisting role =" php" >
254
+ <![CDATA[
255
+ <?php
256
+ interface A
257
+ {
258
+ public function foo(string $s): string;
259
+
260
+ public function bar(int $i): int;
261
+ }
262
+
263
+ // An abstract class may implement only a portion of an interface.
264
+ // Classes that extend the abstract class must implement the rest.
265
+ abstract class B implements A
266
+ {
267
+ pubic function foo(string $s): string
268
+ {
269
+ return $s . PHP_EOL;
270
+ }
271
+ }
272
+
273
+ class C extends B
274
+ {
275
+ public function bar(int $i): int
276
+ {
277
+ return $i * 2;
278
+ }
279
+ }
280
+ ?>
281
+ ]]>
282
+ </programlisting >
283
+ </example >
284
+ <example xml : id =" language.oop5.interfaces.examples.ex6" >
285
+ <title >Extending and implementing simultaneously</title >
286
+ <programlisting role =" php" >
287
+ <![CDATA[
288
+ <?php
289
+
290
+ class One
291
+ {
292
+ /* ... */
293
+ }
294
+
295
+ interface Usable
296
+ {
297
+ /* ... */
298
+ }
299
+
300
+ interface Updatable
301
+ {
302
+ /* ... */
303
+ }
304
+
305
+ // The keyword order here is important. 'extends' must come first.
306
+ class Two extends One implements Usable, Updatable
215
307
{
216
- const b = 'Class constant';
308
+ /* ... */
217
309
}
218
310
?>
219
311
]]>
0 commit comments