Как использовать сложный объект в качестве ключей в ассоциативных массивах в PHP? - PullRequest
0 голосов
/ 25 ноября 2018

Я хотел бы получить значения для набора значений:

>>> 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

Ответы [ 2 ]

0 голосов
/ 25 ноября 2018

Просматривая документацию по 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.Мне немного грустно по этому поводу.Так что ваша неэффективная функция будет не слишком неэффективной в конце.

0 голосов
/ 25 ноября 2018

Согласно php, ручные массивы и объекты нельзя использовать в качестве ключей массива.

Что вы можете сделать, это:

>>> 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

Я надеюсь, что это помогает.

...