language/oop5/abstract.xml
c1f37a6c270aadbbb3da56a3973ffd62197adf2b
...
...
@@ -4,73 +4,86 @@
4
4
<title>Class Abstraction</title>
5
5

6
6
<para>
7
-
PHP 5 introduces abstract classes and methods. Classes defined as
8
-
abstract cannot be instantiated, and any class that
9
-
contains at least one abstract method must also be abstract. Methods
10
-
defined as abstract simply declare the method's signature - they cannot
11
-
define the implementation.
7
+
PHP has abstract classes, methods, and properties.
8
+
Classes defined as abstract cannot be instantiated, and any class that
9
+
contains at least one abstract method or property must also be abstract.
10
+
Methods defined as abstract simply declare the method's signature and whether it is public or protected;
11
+
they cannot define the implementation. Properties defined as abstract
12
+
may declare a requirement for <literal>get</literal> or <literal>set</literal>
13
+
behavior, and may provide an implementation for one, but not both, operations.
12
14
</para>
13
15

14
16
<para>
15
17
When inheriting from an abstract class, all methods marked abstract in
16
-
the parent's class declaration must be defined by the child; additionally,
17
-
these methods must be defined with the same (or a less restricted)
18
-
<link linkend="language.oop5.visibility">visibility</link>. For example,
19
-
if the abstract method is defined as protected, the function implementation
20
-
must be defined as either protected or public, but not private. Furthermore
21
-
the signatures of the methods must match, i.e. the type hints and the number
22
-
of required arguments must be the same. For example, if the child class
23
-
defines an optional argument, where the abstract method's signature does
24
-
not, there is no conflict in the signature. This also applies to constructors
25
-
as of PHP 5.4. Before 5.4 constructor signatures could differ.
18
+
the parent's class declaration must be defined by the child class,
19
+
and follow the usual
20
+
<link linkend="language.oop5.inheritance">inheritance</link> and
21
+
<link linkend="language.oop.lsp">signature compatibility</link> rules.
26
22
</para>
27
23

24
+
<simpara>
25
+
As of PHP 8.4, an abstract class may declare an abstract property, either public or protected.
26
+
A protected abstract property may be satisfied by a property that is readable/writeable from either
27
+
protected or public scope.
28
+
</simpara>
29
+
<simpara>
30
+
An abstract property may be satisfied either by a standard property or by a property
31
+
with defined <link linkend="language.oop5.property-hooks">hooks</link>, corresponding to the required operation.
32
+
</simpara>
33
+

28
34
<example>
29
-
<title>Abstract class example</title>
30
-
<programlisting role="php">
35
+
<title>Abstract method example</title>
36
+
<programlisting role="php">
31
37
<![CDATA[
32
38
<?php
39
+

33
40
abstract class AbstractClass
34
41
{
35
-
// Force Extending class to define this method
42
+
// Force extending class to define this method
36
43
abstract protected function getValue();
37
44
abstract protected function prefixValue($prefix);
38
45

39
46
// Common method
40
-
public function printOut() {
47
+
public function printOut()
48
+
{
41
49
print $this->getValue() . "\n";
42
50
}
43
51
}
44
52

45
53
class ConcreteClass1 extends AbstractClass
46
54
{
47
-
protected function getValue() {
55
+
protected function getValue()
56
+
{
48
57
return "ConcreteClass1";
49
58
}
50
59

51
-
public function prefixValue($prefix) {
60
+
public function prefixValue($prefix)
61
+
{
52
62
return "{$prefix}ConcreteClass1";
53
63
}
54
64
}
55
65

56
66
class ConcreteClass2 extends AbstractClass
57
67
{
58
-
public function getValue() {
68
+
public function getValue()
69
+
{
59
70
return "ConcreteClass2";
60
71
}
61
72

62
-
public function prefixValue($prefix) {
73
+
public function prefixValue($prefix)
74
+
{
63
75
return "{$prefix}ConcreteClass2";
64
76
}
65
77
}
66
78

67
-
$class1 = new ConcreteClass1;
79
+
$class1 = new ConcreteClass1();
68
80
$class1->printOut();
69
-
echo $class1->prefixValue('FOO_') ."\n";
81
+
echo $class1->prefixValue('FOO_'), "\n";
70
82

71
-
$class2 = new ConcreteClass2;
83
+
$class2 = new ConcreteClass2();
72
84
$class2->printOut();
73
-
echo $class2->prefixValue('FOO_') ."\n";
85
+
echo $class2->prefixValue('FOO_'), "\n";
86
+

74
87
?>
75
88
]]>
76
89
</programlisting>
...
...
@@ -86,22 +99,22 @@ FOO_ConcreteClass2
86
99
</example>
87
100

88
101
<example>
89
-
<title>Abstract class example</title>
102
+
<title>Abstract method example</title>
90
103
<programlisting role="php">
91
104
<![CDATA[
92
105
<?php
106
+

93
107
abstract class AbstractClass
94
108
{
95
-
// Our abstract method only needs to define the required arguments
109
+
// An abstract method only needs to define the required arguments
96
110
abstract protected function prefixName($name);
97
-

98
111
}
99
112

100
113
class ConcreteClass extends AbstractClass
101
114
{
102
-

103
-
// Our child class may define optional arguments not in the parent's signature
104
-
public function prefixName($name, $separator = ".") {
115
+
// A child class may define optional parameters which are not present in the parent's signature
116
+
public function prefixName($name, $separator = ".")
117
+
{
105
118
if ($name == "Pacman") {
106
119
$prefix = "Mr";
107
120
} elseif ($name == "Pacwoman") {
...
...
@@ -109,13 +122,15 @@ class ConcreteClass extends AbstractClass
109
122
} else {
110
123
$prefix = "";
111
124
}
125
+

112
126
return "{$prefix}{$separator} {$name}";
113
127
}
114
128
}
115
129

116
-
$class = new ConcreteClass;
130
+
$class = new ConcreteClass();
117
131
echo $class->prefixName("Pacman"), "\n";
118
132
echo $class->prefixName("Pacwoman"), "\n";
133
+

119
134
?>
120
135
]]>
121
136
</programlisting>
...
...
@@ -127,13 +142,81 @@ Mrs. Pacwoman
127
142
]]>
128
143
</screen>
129
144
</example>
145
+
<example>
146
+
<title>Abstract property example</title>
147
+
<programlisting role="php">
148
+
<![CDATA[
149
+
<?php
130
150

131
-
<para>
132
-
Old code that has no user-defined classes or functions named
133
-
'abstract' should run without modifications.
134
-
</para>
135
-
</sect1>
151
+
abstract class A
152
+
{
153
+
// Extending classes must have a publicly-gettable property
154
+
abstract public string $readable {
155
+
get;
156
+
}
157
+

158
+
// Extending classes must have a protected- or public-writeable property
159
+
abstract protected string $writeable {
160
+
set;
161
+
}
162
+

163
+
// Extending classes must have a protected or public symmetric property
164
+
abstract protected string $both {
165
+
get;
166
+
set;
167
+
}
168
+
}
169
+

170
+
class C extends A
171
+
{
172
+
// This satisfies the requirement and also makes it settable, which is valid
173
+
public string $readable;
174
+

175
+
// This would NOT satisfy the requirement, as it is not publicly readable
176
+
protected string $readable;
177
+

178
+
// This satisfies the requirement exactly, so is sufficient.
179
+
// It may only be written to, and only from protected scope
180
+
protected string $writeable {
181
+
set => $value;
182
+
}
183
+

184
+
// This expands the visibility from protected to public, which is fine
185
+
public string $both;
186
+
}
187
+

188
+
?>
189
+
]]>
190
+
</programlisting>
191
+
</example>
192
+
<simpara>
193
+
An abstract property on an abstract class may provide implementations for any hook,
194
+
but must have either <literal>get</literal> or <literal>set</literal> declared but not defined (as in the example above).
195
+
</simpara>
196
+
<example>
197
+
<title>Abstract property with hooks example</title>
198
+
<programlisting role="php" annotations="non-interactive">
199
+
<![CDATA[
200
+
<?php
201
+

202
+
abstract class A
203
+
{
204
+
// This provides a default (but overridable) set implementation,
205
+
// and requires child classes to provide a get implementation
206
+
abstract public string $foo {
207
+
get;
208
+

209
+
set {
210
+
$this->foo = $value;
211
+
}
212
+
}
213
+
}
136
214

215
+
?>
216
+
]]>
217
+
</programlisting>
218
+
</example>
219
+
</sect1>
137
220
<!-- Keep this comment at the end of the file
138
221
Local variables:
139
222
mode: sgml
140
223