是否可以从闭包创建一个命名函数?

In PHP, you can have named functions like this:

function foo()
{
   return "bar";
}

And you can have Closures like this:

$foo = function() {
    return "bar";
};

Closures are awesome and easy to create, but unfortunately a library I need to use really wants a named function. Is it possible to create a named function from closures dynamically? I.e. not defining all functions in code ahead of time, but more like a register_function($name, callable $closure).

I am aware of create_function, but that one takes a PHP string as function body and just evals it, which is not what I'm looking for.

I don't think if it is possible to create named functions out of closures on the fly but using __call() magic method of a class, you may find this workaround helpful:

<?php

class Foo
{
    public function __call($name, $args)
    {
        if (isset($this->{$name}))
            return call_user_func_array($this->{$name}, $args);
    }
}

$foo = new Foo();
// Declaring a closure then assign it to $bar property of Foo
$foo->bar = function () { 
    echo "bar"; 
};
// Call Foo method of the same name
$foo->bar();

You can create global array with callbacks. Add to this global array by register_func($name, $callback) and call function by call_func($name, $parameter1, $parameter2, ...).

Without using eval I think this is not possible to create named function from callback.

My proposal is to use a static methods because they can be call like simple functions. We can achive this with magic function __callStatic like in this code

<?php

class FunctionsProvider
{
    protected static $closures = [];

    public static function addClosure($name, $closure)
    {
        if (is_callable($closure)) {
            static::$closures[$name] = $closure;
        } else {
            throw new \Exception('Closure is not callable');
        }
    }

    public static function __callStatic($name, $arguments)
    {
        if (array_key_exists($name, static::$closures)) {       
            return call_user_func_array(static::$closures[$name], $arguments);
        } else {
            throw new \Exception('Unknown method');
        }
    }
}

//Lets prepare sample closure
$foo = function() {
    return "bar";
};

FunctionsProvider::addClosure('foo', $foo);

$return = FunctionsProvider::foo();

var_dump($return);

On the output we will get

string(3) "bar"

I managed to create one using evil eval, ReflectionClass and SuperClosure library.

Here's my code:

<?php

function register_function(string $name, Closure $closure)
{
    $serializedBody = (new SuperClosure\Serializer)->serialize($closure);

    $obj = unserialize($serializedBody);
    $reflection = new ReflectionClass($obj);
    $property = $reflection->getProperty('data');
    $property->setAccessible(true);
    $data = $property->getValue($obj);
    $body = preg_replace('/^function \(/', "function {$name} (", $data['code']);

    eval($body);
}

$closure = function($a = 1, $b = 2, $c = 3) {
    var_dump(compact('a', 'b', 'c'));
};

register_function('test', $closure);

var_dump(function_exists('test')); // true

test(13, 2, 3);
// array(3) {
//   ["a"]=>
//   int(13)
//   ["b"]=>
//   int(2)
//   ["c"]=>
//   int(3)
// }

In short, you cannot name a \Closure object in PHP.

While I am sure there is an API to do this, it is not exposed at the PHP level. One could possibly write a C Plugin to expose a User-land php function to name the function.