如何在 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 函数最终不会有太多低效。
我想获取值集合的值:
>>> 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 函数最终不会有太多低效。