CakeFest 2024: The Official CakePHP Conference

Closure::fromCallable

(PHP 7 >= 7.1.0)

Closure::fromCallableConvertis un callable en une fermeture

Description

public static Closure::fromCallable(callable $callback): Closure

Crée et retourne une nouvelle fonction anonyme à partir du callback donnée en utilisant la portée courante. Cette méthode vérifie que callback est appelable dans la portée courante et émet un TypeError si ce n'est pas le cas.

Note:

À partir de PHP 8.1.0, la syntaxe callable de première classe à les mêmes sémantiques que cette méthode.

Liste de paramètres

callback

Le callable à convertir.

Valeurs de retour

Retourne la nouvelle Closure créée ou émet une TypeError si callback n'est pas appelable dans la portée courante.

add a note

User Contributed Notes 3 notes

up
13
igorchernin at yahoo dot com
6 years ago
It seems that the result of the "fromCallable" behaves a little bit different then an original Lambda function.

class A {
private $name;
public function __construct($name)
{
$this->name = $name;
}
}

// test callable
function getName()
{
return $this->name;
}
$bob = new A("Bob");

$cl1 = Closure::fromCallable("getName");
$cl1 = $cl1->bindTo($bob, 'A');

//This will retrieve: Uncaught Error: Cannot access private property A::$name
$result = $cl1();
echo $result;

//But for a Lambda function
$cl2 = function() {
return $this->name;
};
$cl2 = $cl2->bindTo($bob, 'A');
$result = $cl2();

// This will print Bob
echo $result;
up
8
4-lom at live dot de
5 years ago
Sadly, your comparison is incorrect.

// The equivalent to
$cl1 = Closure::fromCallable("getName");
$cl1 = $cl1->bindTo($bob, 'A');

// is most likely this
$cl2 = function() {
return call_user_func_array("getName", func_get_args());
};
$cl2 = $cl2->bindTo($bob, 'A');

Executing one or the other Closure should result in the same access violation error you already postet.

----
A simple PHP 7.0 polyfill could look like this:
----

namespace YourPackage;

/**
* Class Closure
*
* @see \Closure
*/
class Closure
{
/**
* @see \Closure::fromCallable()
* @param callable $callable
* @return \Closure
*/
public static function fromCallable(callable $callable)
{
// In case we've got it native, let's use that native one!
if(method_exists(\Closure::class, 'fromCallable')) {
return \Closure::fromCallable($callable);
}

return function () use ($callable) {
return call_user_func_array($callable, func_get_args());
};
}
}
up
5
nakerlund at gmail dot com
5 years ago
I have two points:

It is possible to use Closure::fromCallable to convert private/protected methods to closures and use them outside the class.

Closure::fromCallable accepts late dynamic bindings using the keyword static if provided as a string.

My code below demonstrate how a private static method can be used as a callback in a function outside the class.

<?php
function myCustomMapper ( Callable $callable, string $str ): string {
return
join(' ', array_map( $callable, explode(' ', $str) ) );
}

class
MyClass {

public static function
mapUCFirst ( string $str ): string {
$privateMethod = 'static::mapper';
$mapper = Closure::fromCallable( $privateMethod );
return
myCustomMapper( $mapper, $str );
}
private static function
mapper ( string $str ): string {
return
ucfirst( $str );
}

}

echo
MyClass::mapUCFirst('four little uncapitalized words');
// Prints: Four Little Uncapitalized Words
?>
To Top