Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Hooks documentation #4094

Merged
merged 25 commits into from
Nov 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions language/constants.xml
Original file line number Diff line number Diff line change
Expand Up @@ -321,6 +321,12 @@ echo ANIMALS[1]; // outputs "cat"
The class method name.
</entry>
</row>
<row xml:id="constant.property">
<entry><constant>__PROPERTY__</constant></entry>
<entry>
Only valid inside a <link linkend="language.oop5.property-hooks">property hook</link>. It is equal to the name of the property.
</entry>
</row>
Comment on lines +324 to +329
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note this also adds the T_PROPERTY_C token to the tokenizer extension.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I... don't know what that means? Is that something relevant for the docs?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, in that it needs to be documented in the appendices/tokens.xml file/page :)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm going to leave this one to @iluuu1994, since he knows what it actually does.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do I still need to do something here? Are we documenting individual tokens?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

According to @Girgias, we need something about T_PROPERTY_C in appendices/tokens.xml. I have no idea what that would be or what it means. I can review and merge a PR from you, however. :-)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've already documented this.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you Gina!

<row xml:id="constant.namespace">
<entry><constant>__NAMESPACE__</constant></entry>
<entry>
Expand Down
1 change: 1 addition & 0 deletions language/oop5.xml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@

&language.oop5.basic;
&language.oop5.properties;
&language.oop5.property-hooks;
&language.oop5.constants;
&language.oop5.autoload;
&language.oop5.decon;
Expand Down
84 changes: 78 additions & 6 deletions language/oop5/abstract.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,13 @@
<title>Class Abstraction</title>

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

<para>
Expand All @@ -19,8 +21,18 @@
<link linkend="language.oop.lsp">signature compatibility</link> rules.
</para>

<para>
As of PHP 8.4, an abstract class may declare an abstract property, either public or protected.
A protected abstract property may be satisfied by a property that is readable/writeable from either
protected or public scope.
Girgias marked this conversation as resolved.
Show resolved Hide resolved
</para>
<para>
An abstract property may be satisfied either by a standard property or by a property
with defined <link linkend="language.oop5.property-hooks">hooks</link>, corresponding to the required operation.
</para>

<example>
<title>Abstract class example</title>
<title>Abstract method example</title>
<programlisting role="php">
<![CDATA[
<?php
Expand Down Expand Up @@ -80,7 +92,7 @@ FOO_ConcreteClass2
</example>

<example>
<title>Abstract class example</title>
<title>Abstract method example</title>
<programlisting role="php">
<![CDATA[
<?php
Expand Down Expand Up @@ -121,6 +133,66 @@ Mrs. Pacwoman
]]>
</screen>
</example>
<example>
<title>Abstract property example</title>
<programlisting role="php">
<![CDATA[
<?php
abstract class A
{
// Extending classes must have a publicly-gettable property.
abstract public string $readable { get; }

// Extending classes must have a protected- or public-writeable property.
abstract protected string $writeable { set; }

// Extending classes must have a protected or public symmetric property.
abstract protected string $both { get; set; }
}

class C extends A
{
// This satisfies the requirement and also makes it settable, which is valid.
public string $readable;

// This would NOT satisfy the requirement, as it is not publicly readable.
protected string $readable;

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

// This expands the visibility from protected to public, which is fine.
public string $both;
}
?>
]]>
</programlisting>
</example>
<para>
An abstract property on an abstract class may provide implementations for any hook,
but must have either <literal>get</literal> or <literal>set</literal> declared but not defined (as in the example above).
</para>
<example>
<title>Abstract property example</title>
<programlisting role="php">
<![CDATA[
<?php
abstract class A
{
// This provides a default (but overridable) set implementation,
// and requires child classes to provide a get implementation.
abstract public string $foo {
get;
set { $this->foo = $value };
}
}
?>
]]>
</programlisting>
</example>
</sect1>
<!-- Keep this comment at the end of the file
Local variables:
Expand Down
81 changes: 79 additions & 2 deletions language/oop5/interfaces.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
<sect1 xml:id="language.oop5.interfaces" xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>Object Interfaces</title>
<para>
Object interfaces allow you to create code which specifies which methods a
class must implement, without having to define how these methods are
Object interfaces allow you to create code which specifies which methods and properties a
class must implement, without having to define how these methods or properties are
implemented. Interfaces share a namespace with classes and traits, so they may
not use the same name.
</para>
Expand Down Expand Up @@ -89,6 +89,83 @@
Prior to PHP 8.1.0, they cannot be overridden by a class/interface that inherits them.
</para>
</sect2>
<sect2 xml:id="language.oop5.interfaces.properties">
<title>Properties</title>
<para>
As of PHP 8.4.0, interfaces may also declare properties. If they do, the declaration must specify if the
property is to be readable, writeable, or both. The interface declaration applies only to public read
and write access.
</para>
<para>
An class may satisfy an interface property in multiple ways. It may define a public property. It may
define a public <link linkend="language.oop5.property-hooks.virtual">virtual property</link> that implements
only the corresponding hook. Or a read property may be satisfied by a <literal>readonly</literal> property.
However, an interface property that is settable may not be <literal>readonly</literal>.
</para>
<example>
<title>Interface properties example</title>
<programlisting role="php">
<![CDATA[
<?php
interface I
{
// An implementing class MUST have a publicly-readable property,
// but whether or not it's publicly settable is unrestricted.
public string $readable { get; }

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

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

// This class implements all three properties as traditional, un-hooked
// properties. That's entirely valid.
class C1 implements I
{
public string $readable;

public string $writeable;

public string $both;
}

// This class implements all three properties using just the hooks
// that are requested. This is also entirely valid.
class C2 implements I
{
private string $written = '';
private string $all = '';

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

// The interface only requires the property be settable,
// but also including get operations is entirely valid.
// This example creates a virtual property, which is fine.
public string $writeable {
get => $this->written;
set => $value;
}

// This property requires both read and write be possible,
// so we need to either implement both, or allow it to have
// the default behavior.
public string $both {
get => $this->all;
set => strtoupper($value);
}
}
?>
]]>
</programlisting>
</example>
</sect2>
<sect2 xml:id="language.oop5.interfaces.examples">
&reftitle.examples;
<example xml:id="language.oop5.interfaces.examples.ex1">
Expand Down
Loading