Closure::fromCallable

(PHP 7 >= 7.1.0)

Closure::fromCallableWandelt ein Callable in eine Closure um

Beschreibung

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

Erzeugt aus dem angegebenen Callback eine neue anonyme Funktion im aktuellen Geltungsbereich und gibt diese zurück. Diese Methode prüft, ob der Callback im aktuellen Bereich aufrufbar ist und wirft einen TypeError, wenn dies nicht der Fall ist.

Hinweis:

Seit PHP 8.1.0 hat Callback-Funktionen als Objekte erster Klasse die gleiche Semantik wie diese Methode.

Parameter-Liste

callback

Das Callable, das umgewandelt werden soll.

Rückgabewerte

Gibt die neu erstellte Closure zurück oder wirft einen TypeError, wenn der callback nicht im aktuellen Geltungsbereich aufrufbar ist.

add a note add a note

User Contributed Notes 3 notes

up
17
igorchernin at yahoo dot com
7 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
5
4-lom at live dot de
6 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
4
nakerlund at gmail dot com
6 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