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

时间:2010-09-13 20:40:19

标签: php arrays multidimensional-array eval

我有一些用于对数据进行排序的逻辑,但根据用户输入,数据的分组方式不同。现在我有五个不同的功能,包含相同的逻辑但不同的分组。有没有办法组合这些功能,并动态设置一个正确分组的值。在功能中,这些任务正在发生

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

$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 []数组中的键,这样我就可以拥有一个函数而不是具有不同数组键的多个函数?

6 个答案:

答案 0 :(得分:0)

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

$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();
}

以前给出它,看看阵列结构是如何出现的。

答案 1 :(得分:0)

尝试使用开关盒。

<?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;
    }
}
?>

答案 2 :(得分:0)

我同意@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;
}

另一方面,如果要使用对象,可以创建MeterReading对象类型,然后将MeterReading个实例作为数组元素添加到$calcs数组中,如此:

// 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>';
}

显然你可以更进一步,例如检查对象构造函数中是否存在数组键,如果没有提供,则给对象属性resource一个默认值,依此类推,但这是一个开始OO方法。

答案 3 :(得分:0)

如果要动态设置和设置数组值,可以使用此方法。

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,array('foo','bar','2017-08'))将返回相当于$data['foo']['bar']['2017-08']

的内容

调用setVal($data,array('foo','bar','2017-08'),'hello')将设置值,就像您调用了一样 $data['foo']['bar']['2017-08'] = 'hello'。不存在的密钥将由 php magic 自动创建。

如果要动态构建数组结构,这可能很有用。

答案 4 :(得分:0)

这是我为在数组或对象上设置深层嵌套成员而编写的函数:

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.[]

答案 5 :(得分:0)

您可以使用this library通过键数组来获取或设置多维数组中的值:

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设置为值。