php 使用字符串路径设置嵌套数组数据
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/9628176/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Using a string path to set nested array data
提问by Anthony
I have an unusual use-case I'm trying to code for. The goal is this: I want the customer to be able to provide a string, such as:
我有一个不寻常的用例,我正在尝试编码。目标是这样的:我希望客户能够提供一个字符串,例如:
"cars.honda.civic = On"
Using this string, my code will set a value as follows:
使用此字符串,我的代码将设置如下值:
$data['cars']['honda']['civic'] = 'On';
It's easy enough to tokenize the customer input as such:
将客户输入标记为这样很容易:
$token = explode("=",$input);
$value = trim($token[1]);
$path = trim($token[0]);
$exploded_path = explode(".",$path);
But now, how do I use $exploded path to set the array without doing something nasty like an eval?
但是现在,我如何使用 $exploded path 来设置数组而不做一些像 eval 这样令人讨厌的事情?
回答by alexisdm
Use the reference operator to get the successive existing arrays:
使用引用运算符获取连续的现有数组:
$temp = &$data;
foreach($exploded as $key) {
$temp = &$temp[$key];
}
$temp = $value;
unset($temp);
回答by Ugo Méda
Based on alexisdm's response:
基于alexisdm 的回应:
/**
* Sets a value in a nested array based on path
* See https://stackoverflow.com/a/9628276/419887
*
* @param array $array The array to modify
* @param string $path The path in the array
* @param mixed $value The value to set
* @param string $delimiter The separator for the path
* @return The previous value
*/
function set_nested_array_value(&$array, $path, &$value, $delimiter = '/') {
$pathParts = explode($delimiter, $path);
$current = &$array;
foreach($pathParts as $key) {
$current = &$current[$key];
}
$backup = $current;
$current = $value;
return $backup;
}
回答by ymakux
Well tested and 100% working code. Set, get, unset values from an array using "parents". The parents can be either array('path', 'to', 'value')
or a string path.to.value
. Based on Drupal's code
经过良好测试和 100% 工作的代码。使用“parents”从数组中设置、获取、取消设置值。父母可以是array('path', 'to', 'value')
或字符串path.to.value
。基于 Drupal 的代码
/**
* @param array $array
* @param array|string $parents
* @param string $glue
* @return mixed
*/
function array_get_value(array &$array, $parents, $glue = '.')
{
if (!is_array($parents)) {
$parents = explode($glue, $parents);
}
$ref = &$array;
foreach ((array) $parents as $parent) {
if (is_array($ref) && array_key_exists($parent, $ref)) {
$ref = &$ref[$parent];
} else {
return null;
}
}
return $ref;
}
/**
* @param array $array
* @param array|string $parents
* @param mixed $value
* @param string $glue
*/
function array_set_value(array &$array, $parents, $value, $glue = '.')
{
if (!is_array($parents)) {
$parents = explode($glue, (string) $parents);
}
$ref = &$array;
foreach ($parents as $parent) {
if (isset($ref) && !is_array($ref)) {
$ref = array();
}
$ref = &$ref[$parent];
}
$ref = $value;
}
/**
* @param array $array
* @param array|string $parents
* @param string $glue
*/
function array_unset_value(&$array, $parents, $glue = '.')
{
if (!is_array($parents)) {
$parents = explode($glue, $parents);
}
$key = array_shift($parents);
if (empty($parents)) {
unset($array[$key]);
} else {
array_unset_value($array[$key], $parents);
}
}
回答by Brad Kent
Based on Ugo Méda's response:
基于Ugo Méda 的回应:
This version
这个版本
- allows you to use it solely as a getter (leave the source array untouched)
- fixes the fatal error issue if a non-array value is encountered (
Cannot create references to/from string offsets nor overloaded objects
)
- 允许您仅将其用作 getter(保持源数组不变)
- 修复遇到非数组值时的致命错误问题 (
Cannot create references to/from string offsets nor overloaded objects
)
no fatal error example
没有致命错误示例
$a = ['foo'=>'not an array'];
arrayPath($a, ['foo','bar'], 'new value');
$a
is now
$a
就是现在
array(
'foo' => array(
'bar' => 'new value',
),
)
Use as a getter
用作吸气剂
$val = arrayPath($a, ['foo','bar']); // returns 'new value' / $a remains the same
Set value to null
将值设置为空
$v = null; // assign null to variable in order to pass by reference
$prevVal = arrayPath($a, ['foo','bar'], $v);
$prevVal
is "new value"$a
is now
$prevVal
是“新价值”$a
是现在
array(
'foo' => array(
'bar' => null,
),
)
/**
* set/return a nested array value
*
* @param array $array the array to modify
* @param array $path the path to the value
* @param mixed $value (optional) value to set
*
* @return mixed previous value
*/
function arrayPath(&$array, $path = array(), &$value = null)
{
$args = func_get_args();
$ref = &$array;
foreach ($path as $key) {
if (!is_array($ref)) {
$ref = array();
}
$ref = &$ref[$key];
}
$prev = $ref;
if (array_key_exists(2, $args)) {
// value param was passed -> we're setting
$ref = $value; // set the value
}
return $prev;
}
回答by deceze
$data = $value;
foreach (array_reverse($exploded_path) as $key) {
$data = array($key => $data);
}
回答by Дмитрий Бульвинов
You need use Symfony PropertyPath
您需要使用 Symfony PropertyPath
<?php
// ...
$person = array();
$accessor->setValue($person, '[first_name]', 'Wouter');
var_dump($accessor->getValue($person, '[first_name]')); // 'Wouter'
// or
// var_dump($person['first_name']); // 'Wouter'
回答by Minwork
This is exactly what this methodis for:
这正是此方法的用途:
Arr::set($array, $keys, $value);
It takes your $array
where the element should be set, and accept $keys
in dot separated format or array of subsequent keys.
它需要您$array
设置元素的位置,并$keys
以点分隔格式或后续键数组接受。
So in your case you can achieve desired result simply by:
因此,在您的情况下,您只需通过以下方式即可获得所需的结果:
$data = Arr::set([], "cars.honda.civic", 'On');
// Which will be equivalent to
$data = [
'cars' => [
'honda' => [
'civic' => 'On',
],
],
];
What's more, $keys
parameter can also accept creating auto index, so you can for example use it like this:
更重要的是,$keys
参数还可以接受创建自动索引,因此您可以像这样使用它:
$data = Arr::set([], "cars.honda.civic.[]", 'On');
// In order to get
$data = [
'cars' => [
'honda' => [
'civic' => ['On'],
],
],
];
回答by Starx
Can't you just do this
你不能这样做吗
$exp = explode(".",$path);
$array[$exp[0]][$exp[1]][$exp[2]] = $value