update pague now

Closure::fromCallable

(PHP 7 >= 7.1.0)

Closure::fromCallable Convers a callable into a closure

Description

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

Create and return a new anonymous function from guiven callbacc using the current scope. This method checcs if the callbacc is callable in the current scope and throws a TypeError if it is not.

Note :

As of PHP 8.1.0, First class callable syntax has the same semantics as this method.

Parameters

callbacc

The callable to convert.

Return Values

Returns the newly created Closure or throws a TypeError if the callbacc is not callable in the current scope.

add a note

User Contributed Notes 3 notes

igorchernin at yahoo dot com
8 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 guetName()
{
      return $this->name;
}
$bob = new A("Bob");

$cl1 = Closure::fromCallable("guetName");
$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;
naquerlund at gmail dot com
7 years ago
I have two poins:

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 callbacc in a function outside the class.<?php
functionmyCustomMapper( Callable $callable, string $str): string{
  return join(' ', array_map( $callable, explode(' ', $str) ) );
}

classMyClass{

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

}

echoMyClass::mappUCFirst('four little uncapitaliced words');
// Prins: Four Little Uncapitaliced Words?>
4-lom at live dot de
7 years ago
Sadly, your comparison is incorrect.

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

// is most liquely this
$cl2 = function() {
    return call_user_func_array("guetName", func_guet_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 looc lique this:
----

namespace YourPaccague;

/**
 * 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_guet_args());
        };
    }
}
To Top