Преобразовать точечный синтаксис как "this.that.other" в многомерный массив в PHP
Как следует из названия, я пытаюсь создать парсер и попытаться найти оптимальное решение для преобразования чего-либо из пространства имен точек в многомерный массив таким образом, что
s1.t1.column.1 = size:33%
будет таким же, как
$source['s1']['t1']['column']['1'] = 'size:33%';
Ответы
Ответ 1
Попробуйте этот номер...
function assignArrayByPath(&$arr, $path, $value, $separator='.') {
$keys = explode($separator, $path);
foreach ($keys as $key) {
$arr = &$arr[$key];
}
$arr = $value;
}
CodePad
Он будет прокручивать ключи (по умолчанию ограничено .
), чтобы перейти к окончательному свойству, а затем выполнить присвоение значения.
Если некоторые из клавиш отсутствуют, они создаются.
Ответ 2
К вашему сведению В Laravel у нас есть вспомогательная функция array_set()
которая переводит в эту функцию
Метод для хранения в массиве с использованием точечной нотации
/**
* Set an array item to a given value using "dot" notation.
*
* If no key is given to the method, the entire array will be replaced.
*
* @param array $array
* @param string $key
* @param mixed $value
* @return array
*/
public static function set(&$array, $key, $value)
{
if (is_null($key)) {
return $array = $value;
}
$keys = explode('.', $key);
while (count($keys) > 1) {
$key = array_shift($keys);
// If the key doesn't exist at this depth, we will just create an empty array
// to hold the next value, allowing us to create the arrays to hold final
// values at the correct depth. Then we'll keep digging into the array.
if (! isset($array[$key]) || ! is_array($array[$key])) {
$array[$key] = [];
}
$array = &$array[$key];
}
$array[array_shift($keys)] = $value;
return $array;
}
Это просто как
$array = ['products' => ['desk' => ['price' => 100]]];
array_set($array, 'products.desk.price', 200);
// ['products' => ['desk' => ['price' => 200]]]
Вы можете проверить это в документах
Если вам нужно вместо этого получить данные, используя точечную нотацию, процесс будет немного длиннее, но будет array_get()
на табличке array_get()
которая преобразуется в эту функцию (на самом деле связанный источник показывает вам весь класс, связанный с вспомогательным массивом)
Метод для чтения из массива с использованием точечной нотации
/**
* Get an item from an array using "dot" notation.
*
* @param \ArrayAccess|array $array
* @param string $key
* @param mixed $default
* @return mixed
*/
public static function get($array, $key, $default = null)
{
if (! static::accessible($array)) {
return value($default);
}
if (is_null($key)) {
return $array;
}
if (static::exists($array, $key)) {
return $array[$key];
}
if (strpos($key, '.') === false) {
return $array[$key] ?? value($default);
}
foreach (explode('.', $key) as $segment) {
if (static::accessible($array) && static::exists($array, $segment)) {
$array = $array[$segment];
} else {
return value($default);
}
}
return $array;
}
Как видите, он использует два подметода: available accessible()
и exist exists()
/**
* Determine whether the given value is array accessible.
*
* @param mixed $value
* @return bool
*/
public static function accessible($value)
{
return is_array($value) || $value instanceof ArrayAccess;
}
А также
/**
* Determine if the given key exists in the provided array.
*
* @param \ArrayAccess|array $array
* @param string|int $key
* @return bool
*/
public static function exists($array, $key)
{
if ($array instanceof ArrayAccess) {
return $array->offsetExists($key);
}
return array_key_exists($key, $array);
}
Последнее, что он использует, но вы можете пропустить это, это value()
которое
if (! function_exists('value')) {
/**
* Return the default value of the given value.
*
* @param mixed $value
* @return mixed
*/
function value($value)
{
return $value instanceof Closure ? $value() : $value;
}
}
Ответ 3
Я бы предложил использовать dflydev/dot-access-data.
Если вы не знакомы с использованием Composer, перейдите к https://getcomposer.org/ для введения, чтобы вы могли загружать и автозагружать пакет как зависимость от вашего проекта.
Как только у вас есть пакет, вы можете загрузить многомерный массив в объект Data:
use Dflydev\DotAccessData\Data;
$data = new Data(array(
's1' => array(
't1' => array(
'column' => array(
'1' => 'size:33%',
),
),
),
);
И получить доступ к значениям с помощью точечной нотации:
$size = $username = $data->get('s1.t1.column.1');
Ответ 4
Хотя pasrse_ini_file() также может выводить многомерный массив, я представлю другое решение. Zend_Config_Ini()
$conf = new Zend_COnfig_Ini("path/to/file.ini");
echo $conf -> one -> two -> three; // This is how easy it is to do so
//prints one.two.three
Ответ 5
Я уверен, что вы пытаетесь сделать это, чтобы сохранить некоторые данные конфигурации или аналогичные.
Я настоятельно рекомендую вам сохранить такой файл как .ini
и использовать parse_ini_file() для изменения данных конфигурации в многомерном массиве. Так просто, как это
$confArray = parse_ini_file("filename.ini");
var_dump($confArray);
Ответ 6
Быстрая и грязная...
<?php
$input = 'one.two.three = four';
list($key, $value) = explode('=', $input);
foreach (explode('.', $key) as $keyName) {
if (false === isset($source)) {
$source = array();
$sourceRef = &$source;
}
$keyName = trim($keyName);
$sourceRef = &$sourceRef[$keyName];
}
$sourceRef = $value;
unset($sourceRef);
var_dump($source);
Ответ 7
Я нашел решение, которое работало для меня: Преобразовать плоский PHP Array в Nested Array на основе Array Keys, и, поскольку у меня был массив, основанный на INI файле с различными ключами, я сделал небольшую модификацию этого скрипта и сделал для меня работу.
Мой массив выглядел так:
[resources.db.adapter] => PDO_MYSQL
[resources.db.params.host] => localhost
[resources.db.params.dbname] => qwer
[resources.db.params.username] => asdf
...
По запросу, этот код, который я описал, работал для меня:
<?php
echo "remove the exit :-)"; exit;
$db_settings = parse_ini_file($_SERVER['DOCUMENT_ROOT'].'/website/var/config/app.ini');
echo "<pre>";
print_r($db_settings);
echo "</pre>";
$resources = array();
foreach ($db_settings as $path => $value) {
$ancestors = explode('.', $path);
set_nested_value($resources, $ancestors, $value);
}
echo "<pre>";
print_r($resources);
echo "</pre>";
/**
* Give it and array, and an array of parents, it will decent into the
* nested arrays and set the value.
*/
function set_nested_value(array &$arr, array $ancestors, $value) {
$current = &$arr;
foreach ($ancestors as $key) {
// To handle the original input, if an item is not an array,
// replace it with an array with the value as the first item.
if (!is_array($current)) {
$current = array( $current);
}
if (!array_key_exists($key, $current)) {
$current[$key] = array();
}
$current = &$current[$key];
}
$current = $value;
}
Это источник INI файла, читаемого parse_ini_file():
Array
(
[resources.db.adapter] => PDO_MYSQL
[resources.db.params.host] => localhost
[resources.db.params.dbname] => dbname
[resources.db.params.username] => dbname_user
[resources.db.params.password] => qwerqwerqwerqwer
[resources.db.params.charset] => utf8
[externaldb.adapter] => PDO_MYSQL
[externaldb.params.host] => localhost
[externaldb.params.dbname] => dbname2
[externaldb.params.username] => dbname_user2
[externaldb.params.password] => qwerqwerwqerqerw
[externaldb.params.charset] => latin1
)
Это результат кода выше:
Array
(
[resources] => Array
(
[db] => Array
(
[adapter] => PDO_MYSQL
[params] => Array
(
[host] => localhost
[dbname] => dbname
[username] => dbname_user
[password] => qwerqwerqwerqwer
[charset] => utf8
)
)
)
[externaldb] => Array
(
[adapter] => PDO_MYSQL
[params] => Array
(
[host] => localhost
[dbname] => dbname2
[username] => dbname_user2
[password] => qwerqwerwqerqerw
[charset] => latin1
)
)
)