Skip to content

Commit 2c87ae8

Browse files
committed
Document inheritance.
1 parent 23975d4 commit 2c87ae8

File tree

1 file changed

+150
-0
lines changed

1 file changed

+150
-0
lines changed

language/oop5/property-hooks.xml

Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -303,7 +303,157 @@ class Person {
303303
elements of the array require special care.
304304
</para>
305305
</sect2>
306+
<sect2>
307+
<title>Inheritance</title>
308+
<sect3>
309+
<title>Final hooks</title>
310+
<para>
311+
Hooks may also be declared final, in which case they may not be overridden.
312+
</para>
313+
<example>
314+
<title>Final hooks</title>
315+
<programlisting role="php">
316+
<![CDATA[
317+
<?php
318+
class User
319+
{
320+
public string $username {
321+
final set => strtolower($value);
322+
}
323+
}
324+
325+
class Manager extends User
326+
{
327+
public string $username {
328+
// This is allowed
329+
get => strtoupper($this->username);
306330
331+
// But this is NOT allowed, because set is final in the parent.
332+
set => strtoupper($value);
333+
}
334+
}
335+
?>
336+
]]>
337+
</programlisting>
338+
</example>
339+
<para>
340+
A property may also be declared <link linkend="language.oop5.final">final</link>.
341+
A final property may not be redeclared by a child class in any way, which precludes
342+
altering hooks or widening its access.
343+
</para>
344+
<para>
345+
Declaring hooks final on a property that is declared final is redundant,
346+
and will be silently ignored. This is the same behavior as final methods.
347+
</para>
348+
</sect3>
349+
<para>
350+
A child class may define or redefine individual hooks on a property by redefining the property
351+
and just the hooks it wishes to override. A child class may also add hooks to a property that had none.
352+
This is essentially the same as if the hooks were methods.
353+
</para>
354+
<example>
355+
<title>Hook inheritance</title>
356+
<programlisting role="php">
357+
<![CDATA[
358+
<?php
359+
class Point
360+
{
361+
public int $x;
362+
public int $y;
363+
}
364+
365+
class PositivePoint extends Point
366+
{
367+
public int $x {
368+
set {
369+
if ($value < 0) {
370+
throw new \InvalidArgumentException('Too small');
371+
}
372+
$this->x = $value;
373+
}
374+
}
375+
}
376+
?>
377+
]]>
378+
</programlisting>
379+
</example>
380+
<para>
381+
Each hook overrides parent implementations independently of each other.
382+
If a child class adds hooks, any default value set on the property is removed, and must be redeclared.
383+
That is the same consistent with how inheritance works on hook-less properties.
384+
</para>
385+
<sect3>
386+
<title>Accessing parent hooks</title>
387+
<para>
388+
A hook in a child class may access the parent class's property using the <code>parent::$prop</code> keyword,
389+
followed by the desired hook. For example, <code>parent::$propName::get()</code>.
390+
It may be read as “access the <varname>prop</varname> defined on the parent class,
391+
and then run its get operation” (or set operation, as appropriate).
392+
</para>
393+
<para>
394+
If not accessed this way, the parent class's hook is ignored. This behavior is consistent with how all methods work.
395+
This also offers a way to access the parent class's storage, if any.
396+
If there is no hook on the parent property, its default get/set behavior will be used.
397+
Hooks may not access any other hook except their own parent on their own property.
398+
</para>
399+
<para>
400+
The example above could be rewritten more efficiently as follows.
401+
</para>
402+
<example>
403+
<title>Parent hook access (set)</title>
404+
<programlisting role="php">
405+
<![CDATA[
406+
<?php
407+
class Point
408+
{
409+
public int $x;
410+
public int $y;
411+
}
412+
413+
class PositivePoint extends Point
414+
{
415+
public int $x {
416+
set {
417+
if ($value < 0) {
418+
throw new \InvalidArgumentException('Too small');
419+
}
420+
$this->x = $value;
421+
}
422+
}
423+
}
424+
?>
425+
]]>
426+
</programlisting>
427+
</example>
428+
<para>
429+
An example of overriding only a get hook could be:
430+
</para>
431+
<example>
432+
<title>Parent hook access (get)</title>
433+
<programlisting role="php">
434+
<![CDATA[
435+
<?php
436+
class Strings
437+
{
438+
public string $val;
439+
}
440+
441+
class CaseFoldingStrings extends Strings
442+
{
443+
public bool $uppercase = true;
444+
445+
public string $val {
446+
get => $this->uppercase
447+
? strtoupper(parent::$val::get())
448+
: strtolower(parent::$val::get());
449+
}
450+
}
451+
?>
452+
]]>
453+
</programlisting>
454+
</example>
455+
</sect3>
456+
</sect2>
307457
</sect1>
308458
<!-- Keep this comment at the end of the file
309459
Local variables:

0 commit comments

Comments
 (0)