Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to compute a unique hash for a callable

Tags:

php

I'm trying to write a memoization function, and I just realized this solution does not work when the callback is not a simple string. For example, PHP can accept a callback in the form array($this,'memberFunc'), which is not amenable to serialization.

Then I realized that we don't really want to hash/serialize the whole callback function/object anyway, we just need a unique ID for it so we can check for reference equality. I thought spl_object_hash would do the trick, but it doesn't work on arrays.

Is there another way to generate a unique reference ID for a callable?

like image 475
mpen Avatar asked Nov 27 '13 17:11

mpen


2 Answers

You can always cast to object for hashing purposes:

<?php

class Foo{
    public function __construct(){
        $foo = array($this,'memberFunc');

        var_dump( spl_object_hash((object)$foo) );
        var_dump( spl_object_hash((object)$foo) );
    }
}

new Foo;
string(32) "00000000532ba9fd000000000cc9b0a5"
string(32) "00000000532ba9fd000000000cc9b0a5"
like image 142
Álvaro González Avatar answered Oct 16 '22 19:10

Álvaro González


I wrote this function to get a hash for callables specifically:

/**
 * @param callable $func
 * @return string Unique string identifier for callable instance
 * @throws Exception
 */
private static function callable_hash($func) {
    if(!is_callable($func)) throw new Exception("Function must be a callable");
    if(is_string($func)) {
        return $func;
    } elseif(is_array($func)) {
        if(count($func) !== 2) throw new Exception("Array-callables must have exactly 2 elements");
        if(!is_string($func[1])) throw new Exception("Second element of array-callable must be a string function name");
        if(is_object($func[0])) return spl_object_hash($func[0]).'::'.$func[1];
        elseif(is_string($func[0])) return implode('::',$func);
        throw new Exception("First element of array-callable must be a class name or object instance");
    } elseif(is_object($func)) {
        return spl_object_hash($func);
    }
    throw new Exception("Unhandled callable type");
}

But if Alvaro's solution works... that's much simpler and more flexible.

like image 45
mpen Avatar answered Oct 16 '22 19:10

mpen