[DOC-CVS] [doc-en] master: Rewrite the callback and callable page (#4933)

[email protected] (Kamil Tekiela via GitHub)
Newsgroups php.doc.cvs
Message-ID <[email protected]>
Author: Kamil Tekiela (kamil-tekiela)
Committer: GitHub (web-flow)
Pusher: afilina
Date: 2025-10-31T09:30:09-04:00

Commit: https://github.com/php/doc-en/commit/147b80d1974b969caad1db188a48f4bcd90f5eb8
Raw diff: https://github.com/php/doc-en/commit/147b80d1974b969caad1db188a48f4bcd90f5eb8.diff

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]>

Changed paths:
  M  language/types/callable.xml


Diff:

diff --git a/language/types/callable.xml b/language/types/callable.xml
index d50923a89b6a..3d0d4e900e48 100644
--- a/language/types/callable.xml
+++ b/language/types/callable.xml
@@ -1,71 +1,204 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!-- $Revision$ -->
 <sect1 xml:id="language.types.callable">
- <title>Callbacks / Callables</title>
+ <title>Callables</title>
 
- <para>
-  Callbacks can be denoted by the <type>callable</type> type declaration.
- </para>
+<simpara>
+  A callable is a reference to a function or method that is passed to
+  another function as an argument.
+  They are represented with the <type>callable</type> type declaration.
+</simpara>
+ <informalexample>
+  <programlisting role="php" annotations="non-interactive">
+<![CDATA[
+<?php
+function foo(callable $callback) {
+    $callback();
+}
+?>
+]]>
+  </programlisting>
+ </informalexample>
 
- <para>
-  Some functions like <function>call_user_func</function> or
-  <function>usort</function> accept user-defined callback functions as a
-  parameter. Callback functions can not only be simple functions, but also
-  <type>object</type> methods, including static class methods.
- </para>
+ <simpara>
+  Some functions accept callback functions as a parameter, e.g.
+  <function>array_map</function>, <function>usort</function>, or
+  <function>preg_replace_callback</function>.
+ </simpara>
 
  <sect2 xml:id="language.types.callable.passing">
-  <title>Passing</title>
+  <title>Creation of callables</title>
+
+  <simpara>
+   A callable is a type that represents something that can be invoked.
+   Callables can be passed as arguments to functions or methods which
+   expect a callback parameter or they can be invoked directly.
+   The <type>callable</type> type cannot be used as a type declaration for class
+   properties. Instead, use a <classname>Closure</classname> type declaration.
+  </simpara>
+
+  <simpara>
+   Callables can be created in several different ways:
+  </simpara>
+
+  <itemizedlist>
+   <listitem>
+    <simpara><classname>Closure</classname> object</simpara>
+   </listitem>
+   <listitem>
+    <simpara>&string; containing the name of a function or a method</simpara>
+   </listitem>
+   <listitem>
+    <simpara>
+     &array; containing a class name or an <type>object</type>
+     in index 0 and the method name in index 1
+    </simpara>
+   </listitem>
+   <listitem>
+    <simpara>
+     &object; implementing the <link linkend="object.invoke">__invoke()</link>
+     magic method
+    </simpara>
+   </listitem>
+  </itemizedlist>
+
+  <simpara>
+   A <classname>Closure</classname> object can be created using
+   <link linkend="functions.anonymous">anonymous function</link> syntax,
+   <link linkend="functions.arrow">arrow function</link> syntax,
+   <link linkend="functions.first_class_callable_syntax">first-class callable
+   syntax</link>, or the <methodname>Closure::fromCallable</methodname> method.
+  </simpara>
+
+  <note>
+   <simpara>
+    The <link linkend="functions.first_class_callable_syntax">first-class
+    callable syntax</link> is only available as of PHP 8.1.0.
+   </simpara>
+  </note>
+
+  <example>
+   <title>
+    Callback example using a <classname>Closure</classname>
+   </title>
+  <programlisting role="php">
+<![CDATA[
+<?php
+// Using anonymous function syntax
+$double1 = function ($a) {
+    return $a * 2;
+};
+
+// Using first-class callable syntax
+function double_function($a) {
+    return $a * 2;
+}
+$double2 = double_function(...);
+
+// Using arrow function syntax
+$double3 = fn($a) => $a * 2;
+
+// Using Closure::fromCallable
+$double4 = Closure::fromCallable('double_function');
+
+// Use the closure as a callback here to
+// double the size of each element in our range
+$new_numbers = array_map($double1, range(1, 5));
+print implode(' ', $new_numbers) . PHP_EOL;
+
+$new_numbers = array_map($double2, range(1, 5));
+print implode(' ', $new_numbers) . PHP_EOL;
+
+$new_numbers = array_map($double3, range(1, 5));
+print implode(' ', $new_numbers) . PHP_EOL;
+
+$new_numbers = array_map($double4, range(1, 5));
+print implode(' ', $new_numbers);
+
+?>
+]]>
+   </programlisting>
+   &example.outputs.81;
+   <screen>
+<![CDATA[
+2 4 6 8 10
+2 4 6 8 10
+2 4 6 8 10
+2 4 6 8 10
+]]>
+   </screen>
+  </example>
 
-  <para>
-   A PHP function is passed by either its name as a <type>string</type> or by
-   a <link linkend="functions.first_class_callable_syntax">first-class callable</link>.
+  <simpara>
+   A callable can also be a string containing the name of a function or
+   a static method.
    Any built-in or user-defined function can be used, except language constructs
    such as: <function>array</function>, <function>echo</function>,
    <function>empty</function>, <function>eval</function>,
-   <function>exit</function>, <function>isset</function>,
+   <function>isset</function>,
    <function>list</function>, <function>print</function> or
    <function>unset</function>.
-  </para>
-
-  <para>
-   A method of an instantiated <type>object</type> is passed as an
-   <type>array</type> containing an <type>object</type> at index 0 and the
-   method name at index 1. Accessing protected and private methods from
-   within a class is allowed.
-  </para>
-
-  <para>
-   Static class methods can also be passed without instantiating an
-   <type>object</type> of that class by either, passing the class name
-   instead of an <type>object</type> at index 0, or passing
-   <literal>'ClassName::methodName'</literal>.
-  </para>
-
-  <para>
-   Apart from common user-defined function,
-   <link linkend="functions.anonymous">anonymous functions</link> and
-   <link linkend="functions.arrow">arrow functions</link> can also be
-   passed to a callback parameter.
-  </para>
+  </simpara>
+
+  <simpara>
+   Static class methods can be used without instantiating an
+   <type>object</type> of that class by either, creating an array with
+   the class name at index 0 and the method name at index 1, or by using
+   the special syntax with the scope resolution operator
+   <literal>::</literal>, as in <literal>'ClassName::methodName'</literal>.
+  </simpara>
+
+  <simpara>
+   A method of an instantiated <type>object</type> can be a callable
+   when provided as an array with the <type>object</type> at index 0 and
+   the method name at index 1.
+  </simpara>
+
+  <simpara>
+   The main difference between a <classname>Closure</classname> object and the
+   <type>callable</type> type is that a <classname>Closure</classname> object is
+   scope-independent and can always be invoked, whereas a callable type may be
+   scope-dependent and may not be directly invoked.
+   <classname>Closure</classname> is the preferred way to create callables.
+  </simpara>
+
+  <note>
+   <simpara>
+    While <classname>Closure</classname> objects are bound to the scope
+    where they are created, callables referencing class methods as strings
+    or arrays are resolved in the scope where they are called.
+    To create a callable from a private or protected method, which can then be
+    invoked from outside the class scope, use
+    <methodname>Closure::fromCallable</methodname> or the
+    <link linkend="functions.first_class_callable_syntax">first-class callable
+    syntax</link>.
+   </simpara>
+  </note>
+
+  <simpara>
+   PHP allows the creation of callables which can be used as a callback argument
+   but cannot be called directly.
+   These are context-dependent callables which reference a class method in the
+   inheritance hierarchy of a class, e.g.
+   <literal>'parent::method'</literal> or <literal>["static", "method"]</literal>.
+  </simpara>
 
   <note>
-   <para>
-    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>.
-   </para>
+   <simpara>
+    As of PHP 8.2.0, context-dependent callables
+    are deprecated. Remove the context dependency by replacing
+    <literal>'parent::method'</literal> with
+    <literal>parent::class . '::method'</literal> or use the
+    <link linkend="functions.first_class_callable_syntax">first-class callable
+    syntax</link>.
+   </simpara>
   </note>
 
-  <para>
-   Generally, any object implementing <link linkend="object.invoke">__invoke()</link> can also
-   be passed to a callback parameter.
-  </para>
-
-  <para>
-   <example>
-    <title>
-     Callback function examples
-    </title>
-    <programlisting role="php">
+  <example>
+   <title>
+    Calling various types of callables with <function>call_user_function</function>
+   </title>
+   <programlisting role="php">
 <![CDATA[
 <?php
 
@@ -85,16 +218,19 @@ class MyClass {
 call_user_func('my_callback_function');
 
 // Type 2: Static class method call
-call_user_func(array('MyClass', 'myCallbackMethod'));
+call_user_func(['MyClass', 'myCallbackMethod']);
 
 // Type 3: Object method call
 $obj = new MyClass();
-call_user_func(array($obj, 'myCallbackMethod'));
+call_user_func([$obj, 'myCallbackMethod']);
 
 // Type 4: Static class method call
 call_user_func('MyClass::myCallbackMethod');
 
-// Type 5: Relative static class method call
+// Type 5: Static class method call using ::class keyword
+call_user_func([MyClass::class, 'myCallbackMethod']);
+
+// Type 6: Relative static class method call
 class A {
     public static function who() {
         echo 'A', PHP_EOL;
@@ -107,12 +243,12 @@ class B extends A {
     }
 }
 
-call_user_func(array('B', 'parent::who')); // A, deprecated as of PHP 8.2.0
+call_user_func(['B', 'parent::who']); // deprecated as of PHP 8.2.0
 
-// Type 6: Objects implementing __invoke can be used as callables
+// Type 7: Objects implementing __invoke can be used as callables
 class C {
     public function __invoke($name) {
-        echo 'Hello ', $name, PHP_EOL;
+        echo 'Hello ', $name;
     }
 }
 
@@ -120,42 +256,22 @@ $c = new C();
 call_user_func($c, 'PHP!');
 ?>
 ]]>
-    </programlisting>
-   </example>
-  </para>
-  <para>
-   <example>
-    <title>
-     Callback example using a <classname>Closure</classname>
-    </title>
-   <programlisting role="php">
+   </programlisting>
+   &example.outputs;
+   <screen>
 <![CDATA[
-<?php
-// Our closure
-$double = function($a) {
-    return $a * 2;
-};
-
-// This is our range of numbers
-$numbers = range(1, 5);
+hello world!
+Hello World!
+Hello World!
+Hello World!
+Hello World!
 
-// Use the closure as a callback here to
-// double the size of each element in our
-// range
-$new_numbers = array_map($double, $numbers);
-
-print implode(' ', $new_numbers);
-?>
-]]>
-    </programlisting>
-    &example.outputs;
-    <screen>
-<![CDATA[
-2 4 6 8 10
+Deprecated: Callables of the form ["B", "parent::who"] are deprecated in script on line 41
+A
+Hello PHP!
 ]]>
-    </screen>
-   </example>
-  </para>
+   </screen>
+  </example>
 
   &note.func-callback-exceptions;
  </sect2>
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.