Skip to content

Commit 147b80d

Browse files
kamil-tekielaTimWollaGirgias
authored
Rewrite the callback and callable page (#4933)
* Rewrite the callback and callable page * Remove English ambiguity * Add arrow function example for callables * Add one more example * Add space after function * Replace <para> with <simpara> * Add "magic method" * Remove exit which became a function * Rewrite second paragraph * Revert back to PHP_EOL * Update language/types/callable.xml Co-authored-by: Tim Düsterhus <[email protected]> * Update language/types/callable.xml Co-authored-by: Gina Peter Banyard <[email protected]> * Update language/types/callable.xml Co-authored-by: Gina Peter Banyard <[email protected]> * Update language/types/callable.xml Co-authored-by: Gina Peter Banyard <[email protected]> * Update language/types/callable.xml Co-authored-by: Gina Peter Banyard <[email protected]> * Update language/types/callable.xml Co-authored-by: Gina Peter Banyard <[email protected]> * Update language/types/callable.xml Co-authored-by: Gina Peter Banyard <[email protected]> * Update language/types/callable.xml Co-authored-by: Gina Peter Banyard <[email protected]> * Update language/types/callable.xml Co-authored-by: Gina Peter Banyard <[email protected]> * Add indentation * Use type snippets * Fix typo * Add alternative property type declaration --------- Co-authored-by: Tim Düsterhus <[email protected]> Co-authored-by: Gina Peter Banyard <[email protected]>
1 parent 3a8c3e7 commit 147b80d

File tree

1 file changed

+206
-90
lines changed

1 file changed

+206
-90
lines changed

language/types/callable.xml

Lines changed: 206 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -1,71 +1,204 @@
11
<?xml version="1.0" encoding="utf-8"?>
22
<!-- $Revision$ -->
33
<sect1 xml:id="language.types.callable">
4-
<title>Callbacks / Callables</title>
4+
<title>Callables</title>
55

6-
<para>
7-
Callbacks can be denoted by the <type>callable</type> type declaration.
8-
</para>
6+
<simpara>
7+
A callable is a reference to a function or method that is passed to
8+
another function as an argument.
9+
They are represented with the <type>callable</type> type declaration.
10+
</simpara>
11+
<informalexample>
12+
<programlisting role="php" annotations="non-interactive">
13+
<![CDATA[
14+
<?php
15+
function foo(callable $callback) {
16+
$callback();
17+
}
18+
?>
19+
]]>
20+
</programlisting>
21+
</informalexample>
922

10-
<para>
11-
Some functions like <function>call_user_func</function> or
12-
<function>usort</function> accept user-defined callback functions as a
13-
parameter. Callback functions can not only be simple functions, but also
14-
<type>object</type> methods, including static class methods.
15-
</para>
23+
<simpara>
24+
Some functions accept callback functions as a parameter, e.g.
25+
<function>array_map</function>, <function>usort</function>, or
26+
<function>preg_replace_callback</function>.
27+
</simpara>
1628

1729
<sect2 xml:id="language.types.callable.passing">
18-
<title>Passing</title>
30+
<title>Creation of callables</title>
31+
32+
<simpara>
33+
A callable is a type that represents something that can be invoked.
34+
Callables can be passed as arguments to functions or methods which
35+
expect a callback parameter or they can be invoked directly.
36+
The <type>callable</type> type cannot be used as a type declaration for class
37+
properties. Instead, use a <classname>Closure</classname> type declaration.
38+
</simpara>
39+
40+
<simpara>
41+
Callables can be created in several different ways:
42+
</simpara>
43+
44+
<itemizedlist>
45+
<listitem>
46+
<simpara><classname>Closure</classname> object</simpara>
47+
</listitem>
48+
<listitem>
49+
<simpara>&string; containing the name of a function or a method</simpara>
50+
</listitem>
51+
<listitem>
52+
<simpara>
53+
&array; containing a class name or an <type>object</type>
54+
in index 0 and the method name in index 1
55+
</simpara>
56+
</listitem>
57+
<listitem>
58+
<simpara>
59+
&object; implementing the <link linkend="object.invoke">__invoke()</link>
60+
magic method
61+
</simpara>
62+
</listitem>
63+
</itemizedlist>
64+
65+
<simpara>
66+
A <classname>Closure</classname> object can be created using
67+
<link linkend="functions.anonymous">anonymous function</link> syntax,
68+
<link linkend="functions.arrow">arrow function</link> syntax,
69+
<link linkend="functions.first_class_callable_syntax">first-class callable
70+
syntax</link>, or the <methodname>Closure::fromCallable</methodname> method.
71+
</simpara>
72+
73+
<note>
74+
<simpara>
75+
The <link linkend="functions.first_class_callable_syntax">first-class
76+
callable syntax</link> is only available as of PHP 8.1.0.
77+
</simpara>
78+
</note>
79+
80+
<example>
81+
<title>
82+
Callback example using a <classname>Closure</classname>
83+
</title>
84+
<programlisting role="php">
85+
<![CDATA[
86+
<?php
87+
// Using anonymous function syntax
88+
$double1 = function ($a) {
89+
return $a * 2;
90+
};
91+
92+
// Using first-class callable syntax
93+
function double_function($a) {
94+
return $a * 2;
95+
}
96+
$double2 = double_function(...);
97+
98+
// Using arrow function syntax
99+
$double3 = fn($a) => $a * 2;
100+
101+
// Using Closure::fromCallable
102+
$double4 = Closure::fromCallable('double_function');
103+
104+
// Use the closure as a callback here to
105+
// double the size of each element in our range
106+
$new_numbers = array_map($double1, range(1, 5));
107+
print implode(' ', $new_numbers) . PHP_EOL;
108+
109+
$new_numbers = array_map($double2, range(1, 5));
110+
print implode(' ', $new_numbers) . PHP_EOL;
111+
112+
$new_numbers = array_map($double3, range(1, 5));
113+
print implode(' ', $new_numbers) . PHP_EOL;
114+
115+
$new_numbers = array_map($double4, range(1, 5));
116+
print implode(' ', $new_numbers);
117+
118+
?>
119+
]]>
120+
</programlisting>
121+
&example.outputs.81;
122+
<screen>
123+
<![CDATA[
124+
2 4 6 8 10
125+
2 4 6 8 10
126+
2 4 6 8 10
127+
2 4 6 8 10
128+
]]>
129+
</screen>
130+
</example>
19131

20-
<para>
21-
A PHP function is passed by either its name as a <type>string</type> or by
22-
a <link linkend="functions.first_class_callable_syntax">first-class callable</link>.
132+
<simpara>
133+
A callable can also be a string containing the name of a function or
134+
a static method.
23135
Any built-in or user-defined function can be used, except language constructs
24136
such as: <function>array</function>, <function>echo</function>,
25137
<function>empty</function>, <function>eval</function>,
26-
<function>exit</function>, <function>isset</function>,
138+
<function>isset</function>,
27139
<function>list</function>, <function>print</function> or
28140
<function>unset</function>.
29-
</para>
30-
31-
<para>
32-
A method of an instantiated <type>object</type> is passed as an
33-
<type>array</type> containing an <type>object</type> at index 0 and the
34-
method name at index 1. Accessing protected and private methods from
35-
within a class is allowed.
36-
</para>
37-
38-
<para>
39-
Static class methods can also be passed without instantiating an
40-
<type>object</type> of that class by either, passing the class name
41-
instead of an <type>object</type> at index 0, or passing
42-
<literal>'ClassName::methodName'</literal>.
43-
</para>
44-
45-
<para>
46-
Apart from common user-defined function,
47-
<link linkend="functions.anonymous">anonymous functions</link> and
48-
<link linkend="functions.arrow">arrow functions</link> can also be
49-
passed to a callback parameter.
50-
</para>
141+
</simpara>
142+
143+
<simpara>
144+
Static class methods can be used without instantiating an
145+
<type>object</type> of that class by either, creating an array with
146+
the class name at index 0 and the method name at index 1, or by using
147+
the special syntax with the scope resolution operator
148+
<literal>::</literal>, as in <literal>'ClassName::methodName'</literal>.
149+
</simpara>
150+
151+
<simpara>
152+
A method of an instantiated <type>object</type> can be a callable
153+
when provided as an array with the <type>object</type> at index 0 and
154+
the method name at index 1.
155+
</simpara>
156+
157+
<simpara>
158+
The main difference between a <classname>Closure</classname> object and the
159+
<type>callable</type> type is that a <classname>Closure</classname> object is
160+
scope-independent and can always be invoked, whereas a callable type may be
161+
scope-dependent and may not be directly invoked.
162+
<classname>Closure</classname> is the preferred way to create callables.
163+
</simpara>
164+
165+
<note>
166+
<simpara>
167+
While <classname>Closure</classname> objects are bound to the scope
168+
where they are created, callables referencing class methods as strings
169+
or arrays are resolved in the scope where they are called.
170+
To create a callable from a private or protected method, which can then be
171+
invoked from outside the class scope, use
172+
<methodname>Closure::fromCallable</methodname> or the
173+
<link linkend="functions.first_class_callable_syntax">first-class callable
174+
syntax</link>.
175+
</simpara>
176+
</note>
177+
178+
<simpara>
179+
PHP allows the creation of callables which can be used as a callback argument
180+
but cannot be called directly.
181+
These are context-dependent callables which reference a class method in the
182+
inheritance hierarchy of a class, e.g.
183+
<literal>'parent::method'</literal> or <literal>["static", "method"]</literal>.
184+
</simpara>
51185

52186
<note>
53-
<para>
54-
As of PHP 8.1.0, anonymous functions can also be created using the <link linkend="functions.first_class_callable_syntax">first class callable syntax</link>.
55-
</para>
187+
<simpara>
188+
As of PHP 8.2.0, context-dependent callables
189+
are deprecated. Remove the context dependency by replacing
190+
<literal>'parent::method'</literal> with
191+
<literal>parent::class . '::method'</literal> or use the
192+
<link linkend="functions.first_class_callable_syntax">first-class callable
193+
syntax</link>.
194+
</simpara>
56195
</note>
57196

58-
<para>
59-
Generally, any object implementing <link linkend="object.invoke">__invoke()</link> can also
60-
be passed to a callback parameter.
61-
</para>
62-
63-
<para>
64-
<example>
65-
<title>
66-
Callback function examples
67-
</title>
68-
<programlisting role="php">
197+
<example>
198+
<title>
199+
Calling various types of callables with <function>call_user_function</function>
200+
</title>
201+
<programlisting role="php">
69202
<![CDATA[
70203
<?php
71204
@@ -85,16 +218,19 @@ class MyClass {
85218
call_user_func('my_callback_function');
86219
87220
// Type 2: Static class method call
88-
call_user_func(array('MyClass', 'myCallbackMethod'));
221+
call_user_func(['MyClass', 'myCallbackMethod']);
89222
90223
// Type 3: Object method call
91224
$obj = new MyClass();
92-
call_user_func(array($obj, 'myCallbackMethod'));
225+
call_user_func([$obj, 'myCallbackMethod']);
93226
94227
// Type 4: Static class method call
95228
call_user_func('MyClass::myCallbackMethod');
96229
97-
// Type 5: Relative static class method call
230+
// Type 5: Static class method call using ::class keyword
231+
call_user_func([MyClass::class, 'myCallbackMethod']);
232+
233+
// Type 6: Relative static class method call
98234
class A {
99235
public static function who() {
100236
echo 'A', PHP_EOL;
@@ -107,55 +243,35 @@ class B extends A {
107243
}
108244
}
109245
110-
call_user_func(array('B', 'parent::who')); // A, deprecated as of PHP 8.2.0
246+
call_user_func(['B', 'parent::who']); // deprecated as of PHP 8.2.0
111247
112-
// Type 6: Objects implementing __invoke can be used as callables
248+
// Type 7: Objects implementing __invoke can be used as callables
113249
class C {
114250
public function __invoke($name) {
115-
echo 'Hello ', $name, PHP_EOL;
251+
echo 'Hello ', $name;
116252
}
117253
}
118254
119255
$c = new C();
120256
call_user_func($c, 'PHP!');
121257
?>
122258
]]>
123-
</programlisting>
124-
</example>
125-
</para>
126-
<para>
127-
<example>
128-
<title>
129-
Callback example using a <classname>Closure</classname>
130-
</title>
131-
<programlisting role="php">
259+
</programlisting>
260+
&example.outputs;
261+
<screen>
132262
<![CDATA[
133-
<?php
134-
// Our closure
135-
$double = function($a) {
136-
return $a * 2;
137-
};
138-
139-
// This is our range of numbers
140-
$numbers = range(1, 5);
263+
hello world!
264+
Hello World!
265+
Hello World!
266+
Hello World!
267+
Hello World!
141268
142-
// Use the closure as a callback here to
143-
// double the size of each element in our
144-
// range
145-
$new_numbers = array_map($double, $numbers);
146-
147-
print implode(' ', $new_numbers);
148-
?>
149-
]]>
150-
</programlisting>
151-
&example.outputs;
152-
<screen>
153-
<![CDATA[
154-
2 4 6 8 10
269+
Deprecated: Callables of the form ["B", "parent::who"] are deprecated in script on line 41
270+
A
271+
Hello PHP!
155272
]]>
156-
</screen>
157-
</example>
158-
</para>
273+
</screen>
274+
</example>
159275

160276
&note.func-callback-exceptions;
161277
</sect2>

0 commit comments

Comments
 (0)