Skip to content
Open
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
86 changes: 84 additions & 2 deletions language/types/callable.xml
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,18 @@
<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.
method name at index 1. Passing protected and private methods
with the <type>callable</type> syntax is allowed.
</para>

<note>
<para>
If a callable of a protected or a private method is invoked from outside the class
with no visibility of said methods (e.g. being called from a POSIX signal handler),
Copy link
Contributor

@Crell Crell Oct 3, 2025

Choose a reason for hiding this comment

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

A POSIX signal handler is a very niche example here. I know it's the one that prompted this PR, but I'd use something more common or self-evident.

a runtime error is thrown because the callable is invalid at the time of invocation.
Copy link
Member

Choose a reason for hiding this comment

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

What kind of error?

Copy link
Member

Choose a reason for hiding this comment

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

I don't think this means what you wanted to say. A callable or a closure of a private member can be invoked from outside the class. The problem is only with the pseudo-callables in the form of array which are converted into the actual closure at the invokation time only and therefore refer to an inaccessible member.

This page should probably be entirely rewritten to explain the modern concepts better.

</para>
</note>

<para>
Static class methods can also be passed without instantiating an
<type>object</type> of that class by either, passing the class name
Expand Down Expand Up @@ -156,6 +164,80 @@ print implode(' ', $new_numbers);
</example>
</para>

<para>
<example>
<title>
Manually invoking callbacks
Copy link
Contributor

Choose a reason for hiding this comment

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

Is that the appropriate title here? The example feels a big long and involved, but I don't quite know what it's trying to demonstrate.

</title>
<programlisting role="php">
<![CDATA[
<?php

// define a callback handler that executes the callable (no parameters)
function invokeCallback(callable $theCallback) {
$theCallback();
}

// prints "42"
invokeCallback(function () {
echo "42" . PHP_EOL;
});

// define a callback handler that executes the callable with a parameter
function processNumber(callable $processor, int $theNumber) {
// process a number, and print its result
$result = $processor($theNumber);
echo $result . PHP_EOL;
}

// prints "72"
processNumber(fn ($x) => $x * 3, 24);

// define a class implementing the __invoke method
class NumberTripler
{
public function __invoke($x)
{
return $x * 3;
}
}

// prints "15"
$tripler = new NumberTripler();
processNumber($tripler, 5);

// define a class with a private instance method, to be called with the callable syntax
class HiddenFactory
{
private function hiddenWork()
{
echo "256" . PHP_EOL;
Copy link
Member

Choose a reason for hiding this comment

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

Please don't use PHP_EOL for displaying newline. This constant is for parsing text. Use "\n".

Copy link
Contributor

Choose a reason for hiding this comment

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

Uh, what? No, PHP_EOL is entirely fine to use for output.

Copy link
Member

@kamil-tekiela kamil-tekiela Oct 15, 2025

Choose a reason for hiding this comment

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

It creates inconsistent output on different platforms and could confuse new users. The standard "\n" is shorter, unchangeing and universally understood by most programmers. We should avoid using PHP_EOL in the PHP manual.

}

public function getProof()
{
return Closure::fromCallable([$this, 'hiddenWork']);
Copy link
Contributor

Choose a reason for hiding this comment

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

Using $this->hiddenWork(...) is preferred these days.

}
}

// prints "256"
$factory = new HiddenFactory();
$theProof = $factory->getProof();
invokeCallback($theProof);
?>
</programlisting>
&example.outputs;
<screen>
<![CDATA[
42
72
15
256
]]>
</screen>
</example>
</para>

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

Expand Down