本文介绍了在 PHP 中序列化或散列一个闭包的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这必然会引发设计问题,但我想在 PHP 中序列化或散列一个闭包,以便我拥有该闭包的唯一标识符.

This is bound to beg design questions, but I want to serialize or hash a closure in PHP such that I have a unique identifier for that closure.

我不需要能够从中调用闭包,我只需要一个可以从闭包内部和外部访问的唯一标识符,即接受 close 的方法需要生成一个该闭包的 id,并且闭包本身需要能够生成相同的 id

I don't need to be able to call the closure from that, I just need a unique identifier for it that is accessible from inside and outside of the closure itself, i.e. a method that accepts a closer will need to generate an id for that closure, and the closure itself will need to be able to generate that same id

到目前为止我尝试过的事情:

Things I've tried so far:

$someClass = new SomeClass();

$closure1 = $someClass->closure();

print $closure1();
// Outputs: I am a closure: {closure}

print $someClass->closure();
// Outputs: Catchable fatal error: Object of class Closure could not be converted to string

print serialize($closure1);
// Outputs: Fatal error: Uncaught exception 'Exception' with message 'Serialization of 'Closure' is not allowed'

class SomeClass
{
    function closure()
    {
        return function () { return 'I am a closure: ' . __FUNCTION__; };
    }
}

反射 API 似乎也没有提供任何我可以用来创建 ID 的东西.

The Reflection API doesn't seem to offer anything I might be able to use to create an ID either.

推荐答案

我的解决方案更通用,并且考虑了闭包的静态参数.为了实现这个技巧,您可以在闭包内传递对闭包的引用:

My solution is more general and respects static parameters for closure. To make the trick, you can pass a reference to the closure inside the closure:

class ClosureHash
{
    /**
     * List of hashes
     *
     * @var SplObjectStorage
     */
    protected static $hashes = null;

    /**
     * Returns a hash for closure
     *
     * @param callable $closure
     *
     * @return string
     */
    public static function from(Closure $closure)
    {
        if (!self::$hashes) {
            self::$hashes = new SplObjectStorage();
        }

        if (!isset(self::$hashes[$closure])) {
            $ref  = new ReflectionFunction($closure);
            $file = new SplFileObject($ref->getFileName());
            $file->seek($ref->getStartLine()-1);
            $content = '';
            while ($file->key() < $ref->getEndLine()) {
                $content .= $file->current();
                $file->next();
            }
            self::$hashes[$closure] = md5(json_encode(array(
                $content,
                $ref->getStaticVariables()
            )));
        }
        return self::$hashes[$closure];
    }
}

class Test {

    public function hello($greeting)
    {
        $closure = function ($message) use ($greeting, &$closure) {
            echo "Inside: ", ClosureHash::from($closure), PHP_EOL, "<br>" ;
        };
        return $closure;
    }
}

$obj = new Test();

$closure = $obj->hello('Hello');
$closure('PHP');
echo "Outside: ", ClosureHash::from($closure), PHP_EOL, "<br>";

$another = $obj->hello('Bonjour');
$another('PHP');
echo "Outside: ", ClosureHash::from($another), PHP_EOL, "<br>";

这篇关于在 PHP 中序列化或散列一个闭包的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

10-23 17:49