如何在php中动态设置数组键

如何在php中动态设置数组键,php,arrays,multidimensional-array,eval,Php,Arrays,Multidimensional Array,Eval,我有一些用于对数据进行排序的逻辑,但根据用户的输入,数据分组不同。现在我有五个不同的函数,它们包含相同的逻辑,但是不同的分组。是否有一种方法可以组合这些函数并动态设置一个值,以便正确分组。在函数中,这些赋值正在发生 例如,有时我仅通过以下方式存储计算: $calcs[$meter['UnitType']['name']] = ... 但其他时候需要更具体的分组: $calcs[$meter['Resource']['name']][$meter['UnitType']['name']][dat

我有一些用于对数据进行排序的逻辑,但根据用户的输入,数据分组不同。现在我有五个不同的函数,它们包含相同的逻辑,但是不同的分组。是否有一种方法可以组合这些函数并动态设置一个值,以便正确分组。在函数中,这些赋值正在发生

例如,有时我仅通过以下方式存储计算:

$calcs[$meter['UnitType']['name']] = ...
但其他时候需要更具体的分组:

$calcs[$meter['Resource']['name']][$meter['UnitType']['name']][date('Y-m',$start)] =...
正如您所看到的,它有时存储在一个多维数组中,而有时不存储。我一直在尝试使用eval(),但没有成功(不确定这是正确的方法)。将数据存储在临时变量中并不会真正节省太多,因为有许多嵌套循环和if语句,因此数组必须在多个位置重复

编辑

我希望下面的例子能更好地解释我的问题。这显然是一个简单的版本:

if(){
     $calcs[$meter['UnitType']['name']] = $data;
} else {
    while () {
       $calcs[$meter['UnitType']['name']] = $data;
    }
} 
现在可以使用相同的逻辑,但用于将其存储在不同的键中:

if(){
     $calcs[$meter['Resource']['name']][$meter['UnitType']['name']][date('Y-m',$start)] = $data;
} else {
    while () {
       $calcs[$meter['Resource']['name']][$meter['UnitType']['name']][date('Y-m',$start)] = $data;
    }
} 

有没有一种方法可以提取$calc[]数组中的键,这样我就可以拥有一个函数,而不是拥有具有不同数组键的多个函数?

执行以下操作会不会更容易

$calcs = array(
    $meter['Resource']['name'] => array(
        $meter['UnitType']['name'] => 'Some Value',
        $meter['UnitType']['name2'] => 'Some Value Again'
    ),
);
也可以使用对象

$calcs = new stdClass();
$calcs->{$meter['UnitType']['name']} = 'Some Value';
但我建议您先在数组中构建结构,然后再这样做

$calcs = (object)$calcs_array;
也可以将第一个数组循环到新数组中

$new = array();
$d = date('Y-m',$start);
foreach($meter as $key => $value)
{
    $new[$key]['name'][$d] = array();
}

请提前给出,看看数组结构是如何产生的。

尝试使用开关盒

<?php
$userinput = $calcs[$meter['UnitType']['name']] = $data;;

switch ($userinput) {
  case "useriput1":
    while () {
        $calcs[$meter['Resource']['name']][$meter['UnitType']['name']][date('Y-m',$start)] = $data;
    }
    break;
  case "userinput2":
    while () {
        $calcs[$meter['Resource']['name']][$meter['UnitType']['name']][date('Y-m',$start)] = $data;
    }
    break;

  ...

  default:
    while () {
        $calcs[$meter['Resource']['name']][$meter['UnitType']['name']][date('Y-m',$start)] = $data;
    }
}
?>

我同意@Jake N在OP上的评论,即使用对象可能是更好的方法。尽管如此,如果要使用数组,可以检查条件中是否存在键,如下所示:

if(
    array_key_exists('Resource', $meter)
) {
    $calcs[$meter['Resource']['name']][$meter['UnitType']['name']][date('Y-m',$start)] = $data;
} else {
    $calcs[$meter['UnitType']['name']] = $data;
}
// Object defintion
class MeterReading {
    private $data;
    private $resource;
    private $startDate;
    private $unitType;

    public function __construct(Array $meter, $start, $data) {
        $this->unitType   = $meter['UnitType']['name'];
        $this->resource   = $meter['Resource']['name'];
        $this->startDate  = date('Y-m',$start);
    }

    public function data() {
        return $this->data;
    }

    public function resource() {
        return $this->resource;
    }

    public function startDate() {
        return $this->startDate;
    }

    public function unitType() {
        return $this->unitType;
    }
}

// Example population
$calcs[] = new MeterReading($meter, $start, $data);

// Example usage
foreach($calcs as $calc) {
    if($calc->resource()) {
        echo 'Resource: ' . $calc->resource() . '<br>';
    }
    echo 'Unit Type: ' . $calc->unitType() . '<br>';
    echo 'Start Date: ' . $calc->startDate() . '<br>';
    echo 'Data: ' . $calc->data() . '<br>';
}
另一方面,如果要使用对象,可以创建
MeterReading
对象类型,然后将
MeterReading
实例作为数组元素添加到
$calcs
数组中,如下所示:

if(
    array_key_exists('Resource', $meter)
) {
    $calcs[$meter['Resource']['name']][$meter['UnitType']['name']][date('Y-m',$start)] = $data;
} else {
    $calcs[$meter['UnitType']['name']] = $data;
}
// Object defintion
class MeterReading {
    private $data;
    private $resource;
    private $startDate;
    private $unitType;

    public function __construct(Array $meter, $start, $data) {
        $this->unitType   = $meter['UnitType']['name'];
        $this->resource   = $meter['Resource']['name'];
        $this->startDate  = date('Y-m',$start);
    }

    public function data() {
        return $this->data;
    }

    public function resource() {
        return $this->resource;
    }

    public function startDate() {
        return $this->startDate;
    }

    public function unitType() {
        return $this->unitType;
    }
}

// Example population
$calcs[] = new MeterReading($meter, $start, $data);

// Example usage
foreach($calcs as $calc) {
    if($calc->resource()) {
        echo 'Resource: ' . $calc->resource() . '<br>';
    }
    echo 'Unit Type: ' . $calc->unitType() . '<br>';
    echo 'Start Date: ' . $calc->startDate() . '<br>';
    echo 'Data: ' . $calc->data() . '<br>';
}
//对象定义
类仪表读数{
私人数据;
私人资源;
私人$startDate;
私人$unitType;
公共函数构造(数组$meter、$start、$data){
$this->unitType=$meter['unitType']['name'];
$this->resource=$meter['resource']['name'];
$this->startDate=date('Y-m',$start);
}
公共功能数据(){
返回$this->data;
}
公共职能资源(){
返回$this->resource;
}
公共函数起始日期(){
返回$this->startDate;
}
公共函数unitType(){
返回$this->unitType;
}
}
//样本群体
$calcs[]=新仪表读数($meter,$start,$data);
//示例用法
foreach($calcs作为$calc){
如果($calc->resource()){
回显“资源:”。$calc->Resource()。
; } 回显“单位类型:”。$calc->unitType()。
; 回显“开始日期:”。$calc->startDate()。
; 回显“数据:”。$calc->Data()。
; }

显然,您可以更进一步,例如检查对象构造函数中是否存在数组键,如果未提供,则为对象属性
资源
提供默认值,等等,但这是OO方法的开始。

如果您想动态获取和设置数组值,则可以使用此方法

function getVal($data,$chain){
    $level = $data;
    for($i=0;$i<count($chain);$i++){
        if(isset($level[$chain[$i]]))
            $level = $level[$chain[$i]];
        else
            return null; // key does not exist, return null
    }
    return $level;
}

function setVal(&$data,$chain,$value){
    $level = &$data;
    for($i=0;$i<count($chain);$i++){
        $level = &$level[$chain[$i]]; // set reference (&) in order to change the value of the object
    }
    $level = $value;
}
函数getVal($data,$chain){ $level=$data;
对于($i=0;$i),我编写了一个函数,用于在数组或对象上设置深度嵌套的成员:

function dict_set($var, $path, $val) {
    if(empty($var))
        $var = is_array($var) ? array() : new stdClass();

    $parts = explode('.', $path);
    $ptr =& $var;

    if(is_array($parts))
    foreach($parts as $part) {
        if('[]' == $part) {
            if(is_array($ptr))
                $ptr =& $ptr[];

        } elseif(is_array($ptr)) {
            if(!isset($ptr[$part]))
                $ptr[$part] = array();

            $ptr =& $ptr[$part];

        } elseif(is_object($ptr)) {
            if(!isset($ptr->$part))
                $ptr->$part = array();

            $ptr =& $ptr->$part;
        }
    }

    $ptr = $val;

    return $var;
}
使用您的示例数据:

$array = [];

$array = dict_set($array, 'resource1.unit1.2017-10', 'value1');
$array = dict_set($array, 'resource1.unit2.2017-11', 'value2');
$array = dict_set($array, 'resource2.unit1.2017-10', 'value3');

print_r($array);
输出结果如下:

Array
(
    [resource1] => Array
        (
            [unit1] => Array
                (
                    [2017-10] => value1
                )

            [unit2] => Array
                (
                    [2017-11] => value2
                )

        )

    [resource2] => Array
        (
            [unit1] => Array
                (
                    [2017-10] => value3
                )

        )

)
dict_set()
的第二个参数是点表示法中的
$path
字符串。您可以使用在部分之间带有句点分隔符的动态键来构建它。该函数可用于数组和对象

它还可以使用
[]
作为
$path
的元素,将增量成员附加到深度嵌套数组中。例如:
parent.child.child.[]
您可以使用键数组获取或设置多维数组中的值:

Arr::getNestedElement($calcs, [
    $meter['Resource']['name'], 
    $meter['UnitType']['name'], 
    date('Y-m', $start)
]);
要获得价值或价值:

Arr::handleNestedElement($calcs, [
    $meter['Resource']['name'], 
    $meter['UnitType']['name'], 
    date('Y-m', $start)
], $data);

$data
设置为值。

使用对象可以更好地管理它吗?我实际上不理解这个问题。您是否试图以统一的方式查询这些数据结构?我进行了编辑以帮助解释。希望它能帮到您。您能给出一些示例数据吗?您是否尝试确定密钥的名称是否为UnitType或Resource,或者UnitType和Resource是否确实在键中存储动态内容?@Kramer,为用户输入的值添加占位符。请确保数组统一。我不确定问题是否清楚。我已进行了一些编辑,以帮助解释。