在PHP中序列化或散列Hosure

Tob*_*oby 7 php serialization closures

这必然要求设计问题,但我想在PHP中序列化或散列闭包,这样我就有了该闭包的唯一标识符.

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

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

$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__; };
    }
}
Run Code Online (Sandbox Code Playgroud)

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

lis*_*nko 6

我的解决方案比较笼统,并考虑使用静态参数进行封闭。为了达到这个目的,您可以在闭包内部传递对闭包的引用:

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>";
Run Code Online (Sandbox Code Playgroud)


dua*_*led 5

好的,这是我唯一能想到的:

<?php
$f = function() {
};
$rf = new ReflectionFunction($f);
$pseudounique = $rf->getFileName().$rf->getEndLine();
?>
Run Code Online (Sandbox Code Playgroud)

如果您愿意,可以使用md5或诸如此类的方法对其进行哈希处理.但是,如果函数是从字符串生成的,那么你应该用a来播种uniqid()


hak*_*kre 5

您可以将所有你需要写有你自己的,你自己关闭getId()getHash()或什么的.

示例(演示):

1: Hello world
2: Hello world
Run Code Online (Sandbox Code Playgroud)

第一个闭包(ID:1),在调用上下文中读取ID.第二个闭包(ID:2),从闭包内读取ID(其中自引用).

码:

<?php
/**
 * @link http://stackoverflow.com/questions/13983714/serialize-or-hash-a-closure-in-php
 */

class IdClosure
{
    private $callback;
    private $id;

    private static $sequence = 0;

    final public function __construct(Callable $callback) {
        $this->callback = $callback;
        $this->id = ++IdClosure::$sequence;
    }

    public function __invoke() {
        return call_user_func_array($this->callback, func_get_args());
    }

    public function getId() {
        return $this->id;
    }
}

$hello = new IdClosure(function($text) { echo "Hello $text\n";});
echo $hello->getId(), ": ", $hello('world');

$hello2 = new IdClosure(function($text) use (&$hello2) { echo $hello2->getId(), ": Hello $text\n";} );
$hello2('world');
Run Code Online (Sandbox Code Playgroud)

我不知道这是否适合您的需求,也许它会给您一些想法.我建议spl_object_hash但不理解讨论为什么它没有或最终确实有效.