Как заменить селектор вложенного или многоуровневого массива одной строкой

#php #arrays #string #drupal #syntax

#php #массивы #строка #drupal #синтаксис

Вопрос:

Я пытаюсь заменить селекторы многоуровневого массива одной строкой в PHP. Приведенный ниже код, который я пробовал, выполняется на PHP 7.2.

1.

 $nested_array_selectors = '"my_array"]["my_key"]["my_elemnt"';
var_dump($my_instance->my_object[$nested_array_selectors]);
  

2.

 $nested_array_selectors = 'my_array"]["my_key"]["my_elemnt';
var_dump($my_instance->my_object["$nested_array_selectors"]);
  

3.

 $nested_array_selectors = '["my_array"]["my_key"]["my_elemnt"]';
var_dump($my_instance->my_object$nested_array_selectors);
  

Я ожидаю, что $ nested_array_selectors мог бы работать как $my_instance->my_object["my_array"]["my_key"]["my_element"]; но
1 и 2 возвращают «null», а 3 получает Parse error (конечно).

Это действительно невозможно или кто-нибудь может сказать мне, как это исправить?

Ответ №1:

Что-то вроде этого

 $selectors = ["my_array","my_key","my_elemnt"];

$data = (array)$my_instance->my_object;

foreach($selectors as $k=>$v){
    if(isset($data[$k])){
        $data = $data[$k]; //reduce data by 1 level
    }else{
       $data = false;
       break;
    }
}

print_r($data);
  

По сути, каждый раз, когда вы перебираете «селектор», который существует в массиве, вы уменьшаете массив на 1 уровень, так что, например, если мы начнем с этого

 $data = ['foo'=>['bar'=>['baz'=>1]]];
$selectors = ["foo","bar","baz"];

foreach($selectors as $v){
    print_r($data);
    if(isset($data[$v])){
        $data = $data[$v]; //reduce data by 1 level
    }else{
       $data = false;
       break;
    }
}
echo "n---------- Final ------------n";
print_r($data);
  

Вывод

 Array
(
    [foo] => Array
        (
            [bar] => Array
                (
                    [baz] => 1
                )

        )

)
Array
(
    [bar] => Array
        (
            [baz] => 1
        )

)
Array
(
    [baz] => 1
)

---------- Final ------------
1
  

Песочница

Вы можете увидеть «иллюстрированный» выше, как мы можем перейти к нужному нам элементу. Каждое array приведенное выше состояние $data до уменьшения его на этот уровень селекторов. Итак, следующий за этим показывает результаты его сокращения. Итак, первый массив находится перед применением, "foo" второй — после этого, но перед "bar" и т.д…

Если вы хотите использовать строку для $selectors like с запятыми или что-то еще, достаточно просто использовать explode() or preg_split() , чтобы преобразовать эту строку с некоторым разделителем в массив. Например:

  $selectors = "foo.bar.baz";
 $selectors = explode(".", $selectors ); //["foo","bar","baz"]
 //...
  

PS Я бы использовал реальные данные, если бы они были предоставлены, но на данный момент это единственный способ для меня протестировать и объяснить это.

Кроме того, это, очевидно, хороший кандидат для создания функции из:

 function transverseWithKeys(array $array, $keys, $default=null, $glue='.'){
   if(!is_array($keys)) $keys = explode($glue,$keys);

   foreach($keys as $v){
       if(isset($array[$v])){
           $array= $array[$v]; //reduce data by 1 level
       }else{
           return $default;
       }
   }
   return $array;
}
  

Надеюсь, это поможет.

Комментарии:

1. @ArtisticPhoenix. Спасибо за ваше терпеливое объяснение. У меня небольшая проблема с пониманием вашего кода, это моя вина. Проще сделать, чем сказано для программирования, я попробую.

2. I have a little problem for understanding your code — если вы можете выразить это словами, не стесняйтесь спрашивать, и я попытаюсь это объяснить. Спасибо!

Ответ №2:

То, что вы пытаетесь сделать, не сработает, потому что вы пытаетесь преобразовать переменную в PHP-код. PHP не знает, что это ваше намерение, и не выполняет этот код.

В PHP действительно есть eval() конструкция, которая позволяет вам это сделать.

Осторожно, языковая конструкция eval() очень опасна, поскольку она допускает выполнение произвольного PHP-кода. Таким образом, его использование не рекомендуется. Если вы тщательно проверили, что нет другого варианта, кроме использования этой конструкции, обратите особое внимание на то, чтобы не передавать в нее какие-либо предоставленные пользователем данные без предварительной надлежащей проверки.

В руководстве по PHP для eval объясняется больше.

Вычислить строку как PHP-код

В вашем случае будет работать следующий код.

 $nested_array_selectors = '["my_array"]["my_key"]["my_elemnt"]';
eval('var_dump($my_instance->my_object' . $nested_array_selectors . ')');
  

Комментарии:

1. Спасибо за ответ. Кстати, в моем случае мне нужно: $my_instance->my_object["my_array"]["my_key"]["my_element"]; чтобы $my_instance->my_object["$some_var"] . Или любой другой, который мог бы сократить или интегрировать составные параметры.

2. E. Спасибо. Фактически это самый близкий ответ, но ‘eval’ слишком опасен.