略微加速

PHP官方手册 - 互联网笔记

PHP - Manual: Closure::fromCallable

2024-04-29

Closure::fromCallable

(PHP 7 >= 7.1.0)

Closure::fromCallable将 callable 转换为闭包

说明

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

使用当前范围从给定的 callback 创建并返回一个新的 匿名函数。 此方法检查 callback 函数在作用域是否可调用, 如果不能,就抛出 TypeError

注意:

从 PHP 8.1.0 开始,First-class 可调用语法 的语义与此方法相同。

参数

callback

要转换的回调。

返回值

返回新创建的 Closure, 或者如果 callback 在当前作用域无法调用, 则抛出 TypeError

add a noteadd a note

User Contributed Notes 3 notes

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

官方地址:https://www.php.net/manual/en/closure.fromcallable.php

北京半月雨文化科技有限公司.版权所有 京ICP备12026184号-3