PHPKonf Istanbul PHP Conference 2019 - Call for Papers

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 Closure::fromCallable ( callable $işlev )

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

Değiştirgeler

işlev

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

Dönen Değerler

işlev 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 add a note

User Contributed Notes 3 notes

up
11
igorchernin at yahoo dot com
1 year 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
2
nakerlund at gmail dot com
6 months 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
?>
up
2
4-lom at live dot de
7 months 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());
        };
    }
}
To Top