У меня есть некоторая логика, которая используется для сортировки данных, но в зависимости от пользовательского ввода данные группируются по-разному. Прямо сейчас у меня есть пять различных функций, которые содержат одну и ту же логику, но разные группы. Есть ли способ объединить эти функции и динамически установить значение, которое будет группироваться правильно. Внутри функции эти назначения происходят
Например, иногда я храню вычисления просто:
$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; } } ?>
Я согласен с комментарием к OP by @Jake N, что, возможно, использование объектов – лучший подход. Тем не менее, если вы хотите использовать массивы, вы можете проверить наличие ключей в условном выражении, например:
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
, а затем добавить экземпляры 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.
Вы можете использовать это, если хотите получать и устанавливать значения массива динамически.
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 .
Это может быть полезно, если вы хотите динамически строить структуру массива.
Вот функция, которую я написал для установки глубоко вложенных элементов на массивы или объекты:
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.[]