如何在 PHP 的关联数组中使用复杂对象作为键?

How to use complex object as keys in associative arrays in PHP?

我想获取值集合的值:

>>> class Foo() {}
>>> $v = (object)[42];

>>> $a = [1, 1, 2, 3, 5, Foo::class, 'o_o', $v]
>>> $b = [1, 1, 2, 3, 5, Foo::class, 'o_o', $v]

>>> $data[$a] = 42;
>>> echo $data[$b]
42

我尝试使用 SplObjectStorage,但我需要将 $a 转换为对象,在本例中为 $a != $b,因为它们是不同的实例:

$s = new SplObjectStorage()
$s[$a] = 42
echo $s[$b]
UnexpectedValueException with message 'Object not found'

如何在 PHP 中实现此目的?

在Python中我会使用:

>>> a = (1, 1, 2, 3, 5, Foo, 'o_o', hashable_object)
>>> b = (1, 1, 2, 3, 5, Foo, 'o_o', hashable_object)    
>>> data[a] = 42
>>> print(data[b])
42 

编辑

一个不太有效的解决方案是:

>>> class Foo() {}
>>> $v = (object)[42];

>>> $a = [1, 1, 2, 3, 5, Foo::class, 'o_o', $v]
>>> $b = [1, 1, 2, 3, 5, Foo::class, 'o_o', $v]

>>> $data[serialize($a)] = 42;
>>> echo $data[serialize($b)]
42

According to php manual arrays and objects cannot be used as array keys.

你可以这样做:

>>> class Foo {}
>>> $test = new \stdClass();
>>> $test->{implode([1, 1, 2, 3, 5, Foo::class, 'o_o'])} = 42;
>>> $test->{implode([1, 1, 2, 3, 5, Foo::class, 'o_o'])};
=> 42

我要做的是:

$test->something = [ 42 => [1, 1, 2, 3, 5, Foo::class, 'o_o']];
array_search([1, 1, 2, 3, 5, Foo::class, 'o_o'], $test->something, true);
=> 42

希望对您有所帮助。

通过查看 PHP 文档,我发现 '\Ds\Map' 可从 PECL 获得。有了这个你可以写:

$map = new \Ds\Map();

$v = (object)[41];

$a = [1, 1, 2, 3, 5, 'o_o', $v];
$b = [1, 1, 2, 3, 5, 'o_o', $v];

$map[$a] = 42;

var_dump($map[$b]);

我也看了实现:

https://github.com/php-ds/ext-ds/blob/master/src/ds/ds_htable.c

zval 是用这个函数散列的

static uint32_t get_array_hash(zval *array)
{
    uint32_t                   hash;
    php_serialize_data_t       var_hash;
    smart_str                  buffer = {0};

    PHP_VAR_SERIALIZE_INIT(var_hash);
    php_var_serialize(&buffer, array, &var_hash);
    PHP_VAR_SERIALIZE_DESTROY(var_hash);

    smart_str_0(&buffer);

    if (buffer.s) {
        hash = get_string_hash(buffer.s);
        zend_string_free(buffer.s);
    } else {
        hash = 0;
    }

    return hash;
}

所以在幕后使用的是 serialize 函数。对此我感到有些难过。所以你的 inefficient 函数最终不会有太多低效。