#php #arrays #eval #dynamic-arrays
#php #массивы #вычисление #динамические массивы
Вопрос:
Итак, я написал класс, который может анализировать XML-документы и создавать из них SQL-запросы для обновления или вставки новых строк в зависимости от настроек.
Поскольку скрипт должен работать с любым количеством вложенных блоков, путь к массиву, в который я помещаю все значения, создается динамически, как в следующем примере:
$path = array('field1','field2');
$path = "['".implode("']['",$path)."']";
eval("$array".$path."['value'] = 'test';");
В основном $path
содержит массив, который показывает, насколько глубоко мы находимся в массиве в данный момент, если $path
содержит, например, значения, которые main_table
и field
которые я хочу установить $array['main_table']['field']['value']
в 'test'
Как вы можете видеть, в настоящее время я использую eval для этого, и это отлично работает. Мне просто интересно, есть ли способ сделать это без использования eval.
Что-то вроде $array{$path}['value'] = 'test';
но тогда что-то, что действительно работает.
Есть предложения?
Редактировать
Причина, по которой я ищу альтернативу, заключается в том, что я думаю, что eval — плохая практика.
ВТОРАЯ ПРАВКА
Изменил фактический код на фиктивный, потому что это вызывало много недоразумений.
Комментарии:
1. да, хорошо. Это очень похоже на то, что вы делаете это неправильно. Не могли бы вы, пожалуйста, показать входной XML и выходные данные, которых вы хотите достичь. Возможно, вы сможете заставить это работать с итераторами.
2. о, дорогой бог… Переменная переменных неверна, но это просто.. ааааа <голова разрывается> (без обид, просто шучу)
3. Это лишь небольшая часть всей системы, и она работает отлично. Причина, по которой я делаю это таким образом, заключается в том, что вам нужно иметь возможность задавать таблицу, fieldname и множество других параметров — для каждого блока xml — определяя, что должно произойти с данными. Ничего не происходит «неправильно», за исключением того, что я не хочу использовать eval.
4. Эта вещь могла бы быть полезной 🙂
5. Многие вещи, которые работают идеально, тем не менее, неверны. Хирург может оперировать вас ложкой, если он заточит ее, но это не делает ее менее неправильной. Итак, вместо того, чтобы обижаться, почему бы просто не сделать, как просили, и предоставить входные данные и желаемый результат. В конце концов, это вы спросили и хотите альтернативу этой мерзости выше, а не мы 😉
Ответ №1:
Используйте что-то вроде этого:
/**
* Sets an element of a multidimensional array from an array containing
* the keys for each dimension.
*
* @param array amp;$array The array to manipulate
* @param array $path An array containing keys for each dimension
* @param mixed $value The value that is assigned to the element
*/
function set_recursive(amp;$array, $path, $value)
{
$key = array_shift($path);
if (empty($path)) {
$array[$key] = $value;
} else {
if (!isset($array[$key]) || !is_array($array[$key])) {
$array[$key] = array();
}
set_recursive($array[$key], $path, $value);
}
}
Комментарии:
1. Это определенно сработало бы, однако я надеялся на сокращение, которое позволило бы мне сделать это так же быстро, как с eval.
2. Кстати, я бы рекомендовал заменить
isset
наarray_key_exists
, посколькуisset
вернетfalse
, если ключ установлен какnull
Ответ №2:
Вы можете обойти всю работу счетчика с помощью оператора добавления массива:
$some_array[] = 1; // pushes '1' onto the end of the array
Что касается всего процесса path, я предполагаю, что это в основном странное представление xpath-подобного маршрута через ваш XML-документ… есть ли причина, по которой вы не можете просто использовать эту строку в качестве самого ключа массива?
$this->BLOCKS['/path/to/the/node/you're/working/on][] = array('name' => $name, 'target' => $target);
Комментарии:
1. Я не думаю, что оператор добавления массива работает, если я хочу выполнить два подряд,
$some_array[]['name'] = 'test'
тогда$some_array[]['target'] = 'test'
у меня останется$some_array[0]['name'] = 'test'
и$some_array[1]['target'] = 'target'
, или это можно обойти, выполнив что-нибудь сcurrent()
?2. @Kokos: нет, это каждый раз создавало бы новую. но если вы сделаете это, как я, назначив новый массив, вы сможете добавить все свои элементы одновременно.
3.
= array()
Это определенно то, что я начну использовать, ранее я искал сокращенный вариант PHP-массива, очень похожий= ['field'=>'value']
на Actionscript, я никогда не думал использовать обычный синтаксис в подобных случаях. «Бизнес с путем» — это просто объединение массива с][
, в результате чего получаетсяfield][field][field
, а затем после добавления префикса[
и суффикса]
я бросаю это в eval, чтобы создать массив.
Ответ №3:
Вы можете использовать foreach с переменными variables.
// assuming a base called $array, and the path as in your example:
$path = array('field1','field2');
$$path = $array;
foreach ($path as $v) $$path = $$path[$v];
$$path['value'] = 'test';
Короткий, простой и намного лучше, чем eval.
Комментарии:
1. как это должно работать, если
$$path = $array;
подразумевает преобразование массива в строку?