CakeFest 2024: The Official CakePHP Conference

Closure::fromCallable

(PHP 7 >= 7.1.0)

Closure::fromCallableBir işlevi bir closure yöntemine dönüştürür

Açıklama

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

Geçerli bağlamı kullanarak callback bağımsız değişkeninde belirtilen işlevden yeni bir anonim işlev oluşturur ve döner. Bu yöntem callback işlevinin geçerli bağlamda çağrılabilirliğini sınar ve çağrılabilir değilse bir TypeError yavrular.

Bilginize:

PHP 8.1.0 itibariyle, Birinci sınıf çağrılabilir sözdizimine bu yöntemle aynı sözdizimsel kurallar uygulanmaktadır.

Bağımsız Değişkenler

callback

Dönüştürülecek işlev.

Dönen Değerler

callback işlevi geçerli bağlamda çağrılabiliyorsa yeni oluşturulan Closure ile, çağrılamıyorsa bir TypeError ile döner.

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