language/oop5/interfaces.xml
565bd8b6cf2cae44ae2bc54ef6dbe6ee70ddfefd
...
...
@@ -3,9 +3,9 @@
3
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
-
Object interfaces allow you to create code which specifies which methods a
7
-
class must implement, without having to define how these methods are
8
-
implemented. Interfaces share a namespace with classes and traits, so they may
6
+
Object interfaces allow you to create code which specifies which methods and properties a
7
+
class must implement, without having to define how these methods or properties are
8
+
implemented. Interfaces share a namespace with classes, traits, and enumerations, so they may
9
9
not use the same name.
10
10
</para>
11
11
<para>
...
...
@@ -56,12 +56,6 @@
56
56
so will result in a fatal error. Classes may implement more than one interface
57
57
if desired by separating each interface with a comma.
58
58
</para>
59
-
<warning>
60
-
<para>
61
-
A class can implement two interfaces which define a method with the
62
-
same name, only if the method declaration in both interfaces is identical.
63
-
</para>
64
-
</warning>
65
59
<warning>
66
60
<para>
67
61
A class that implements an interface may use a different name for its parameters than
...
...
@@ -79,19 +73,107 @@
79
73
<note>
80
74
<para>
81
75
The class implementing the interface must declare all methods in the interface
82
-
with a <link linkend="language.oop.lsp">compatible signature</link>.
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.
83
80
</para>
84
81
</note>
85
82
</sect2>
86
83
<!-- Move this to OOP constants page? -->
87
84
<sect2 xml:id="language.oop5.interfaces.constants">
88
-
<title><literal>Constants</literal></title>
85
+
<title>Constants</title>
89
86
<para>
90
87
It's possible for interfaces to have constants. Interface constants work exactly
91
-
like <link linkend="language.oop5.constants">class constants</link> except
92
-
they cannot be overridden by a class/interface that inherits them.
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.
93
90
</para>
94
91
</sect2>
92
+
<sect2 xml:id="language.oop5.interfaces.properties">
93
+
<title>Properties</title>
94
+
<simpara>
95
+
As of PHP 8.4.0, interfaces may also declare properties.
96
+
If they do, the declaration must specify if the property is to be readable,
97
+
writeable, or both.
98
+
The interface declaration applies only to public read and write access.
99
+
</simpara>
100
+
<simpara>
101
+
A class may satisfy an interface property in multiple ways.
102
+
It may define a public property.
103
+
It may define a public
104
+
<link linkend="language.oop5.property-hooks.virtual">virtual property</link>
105
+
that implements only the corresponding hook.
106
+
Or a read property may be satisfied by a <literal>readonly</literal> property.
107
+
However, an interface property that is settable may not be <literal>readonly</literal>.
108
+
</simpara>
109
+
<example>
110
+
<title>Interface properties example</title>
111
+
<programlisting role="php">
112
+
<![CDATA[
113
+
<?php
114
+
interface I
115
+
{
116
+
// An implementing class MUST have a publicly-readable property,
117
+
// but whether or not it's publicly settable is unrestricted.
118
+
public string $readable { get; }
119
+

120
+
// An implementing class MUST have a publicly-writeable property,
121
+
// but whether or not it's publicly readable is unrestricted.
122
+
public string $writeable { set; }
123
+

124
+
// An implementing class MUST have a property that is both publicly
125
+
// readable and publicly writeable.
126
+
public string $both { get; set; }
127
+
}
128
+

129
+
// This class implements all three properties as traditional, un-hooked
130
+
// properties. That's entirely valid.
131
+
class C1 implements I
132
+
{
133
+
public string $readable;
134
+

135
+
public string $writeable;
136
+

137
+
public string $both;
138
+
}
139
+

140
+
// This class implements all three properties using just the hooks
141
+
// that are requested. This is also entirely valid.
142
+
class C2 implements I
143
+
{
144
+
private string $written = '';
145
+
private string $all = '';
146
+

147
+
// Uses only a get hook to create a virtual property.
148
+
// This satisfies the "public get" requirement.
149
+
// It is not writeable, but that is not required by the interface.
150
+
public string $readable { get => strtoupper($this->writeable); }
151
+

152
+
// The interface only requires the property be settable,
153
+
// but also including get operations is entirely valid.
154
+
// This example creates a virtual property, which is fine.
155
+
public string $writeable {
156
+
get => $this->written;
157
+
set {
158
+
$this->written = $value;
159
+
}
160
+
}
161
+

162
+
// This property requires both read and write be possible,
163
+
// so we need to either implement both, or allow it to have
164
+
// the default behavior.
165
+
public string $both {
166
+
get => $this->all;
167
+
set {
168
+
$this->all = strtoupper($value);
169
+
}
170
+
}
171
+
}
172
+
?>
173
+
]]>
174
+
</programlisting>
175
+
</example>
176
+
</sect2>
95
177
<sect2 xml:id="language.oop5.interfaces.examples">
96
178
&reftitle.examples;
97
179
<example xml:id="language.oop5.interfaces.examples.ex1">
...
...
@@ -183,6 +265,33 @@ class D implements B
183
265
}
184
266
}
185
267
?>
268
+
]]>
269
+
</programlisting>
270
+
</example>
271
+
<example xml:id="language.oop5.interfaces.examples.variance.multiple.interfaces">
272
+
<title>Variance compatibility with multiple interfaces</title>
273
+
<programlisting role="php">
274
+
<![CDATA[
275
+
<?php
276
+
class Foo {}
277
+
class Bar extends Foo {}
278
+

279
+
interface A {
280
+
public function myfunc(Foo $arg): Foo;
281
+
}
282
+

283
+
interface B {
284
+
public function myfunc(Bar $arg): Bar;
285
+
}
286
+

287
+
class MyClass implements A, B
288
+
{
289
+
public function myfunc(Foo $arg): Bar
290
+
{
291
+
return new Bar();
292
+
}
293
+
}
294
+
?>
186
295
]]>
187
296
</programlisting>
188
297
</example>
...
...
@@ -238,12 +347,15 @@ interface A
238
347
echo A::B;
239
348

240
349

241
-
// This will however not work because it's not allowed to
242
-
// override constants.
243
350
class B implements A
244
351
{
245
352
const B = 'Class constant';
246
353
}
354
+

355
+
// Prints: Class constant
356
+
// Prior to PHP 8.1.0, this will however not work because it was not
357
+
// allowed to override constants.
358
+
echo B::B;
247
359
?>
248
360
]]>
249
361
</programlisting>
...
...
@@ -264,7 +376,7 @@ interface A
264
376
// Classes that extend the abstract class must implement the rest.
265
377
abstract class B implements A
266
378
{
267
-
pubic function foo(string $s): string
379
+
public function foo(string $s): string
268
380
{
269
381
return $s . PHP_EOL;
270
382
}
271
383