visual studio setters getters generate code and php arrays multidimensional-array

php - studio - ¿Cómo acceder y manipular una matriz multidimensional por nombres de clave/ruta?



php getter setter generator (8)

Tengo que implementar un setter en PHP, que me permite especificar la clave, o subclave, de una matriz (el objetivo), pasando el nombre como un valor de claves separadas por puntos.

Dado el siguiente código:

$arr = array(''a'' => 1, ''b'' => array( ''y'' => 2, ''x'' => array(''z'' => 5, ''w'' => ''abc'') ), ''c'' => null); $key = ''b.x.z''; $path = explode(''.'', $key);

Desde el valor de $key quiero alcanzar el valor 5 de $arr[''b''][''x''][''z''] .

Ahora, dado un valor variable de $key y un valor diferente de $arr (con diferente profundidad).

¿Cómo puedo establecer el valor del elemento referido por $key ?

Para el getter get() escribí este código:

public static function get($name, $default = null) { $setting_path = explode(''.'', $name); $val = $this->settings; foreach ($setting_path as $key) { if(array_key_exists($key, $val)) { $val = $val[$key]; } else { $val = $default; break; } } return $val; }

Escribir un setter es más difícil porque logro alcanzar el elemento correcto (desde la $key ), pero no puedo establecer el valor en la matriz original y no sé cómo especificar las claves de una vez.

¿Debo usar algún tipo de retroceso? ¿O puedo evitarlo?


Aquí un código simple para acceder y manipular la matriz MD. Pero no hay valores.

setter:

eval(''$vars = &$array["'' . implode(''"]["'', explode(''.'', strtolower($dot_seperator_path))) . ''"];''); $vars = $new_value;

adquiridor:

eval(''$vars = $array["'' . implode(''"]["'', explode(''.'', strtolower($dot_seperator_path))) . ''"];''); return $vars;


Como "getter", he usado esto en el pasado:

$array = array(''data'' => array(''one'' => ''first'', ''two'' => ''second'')); $key = ''data.one''; function find($key, $array) { $parts = explode(''.'', $key); foreach ($parts as $part) { $array = $array[$part]; } return $array; } $result = find($key, $array); var_dump($result);


Esta función hace lo mismo que la respuesta aceptada, además se agrega un tercer parámetro por referencia que se establece en verdadero / falso si la clave está presente

function drupal_array_get_nested_value(array &$array, array $parents, &$key_exists = NULL) { $ref = &$array; foreach ($parents as $parent) { if (is_array($ref) && array_key_exists($parent, $ref)) { $ref = &$ref[$parent]; } else { $key_exists = FALSE; $null = NULL; return $null; } } $key_exists = TRUE; return $ref; }


No tengo una solución para usted en PHP puro, sino que Arrays::getNestedValue objetos ouzo Arrays::getNestedValue método:

$arr = array(''a'' => 1, ''b'' => array( ''y'' => 2, ''x'' => array(''z'' => 5, ''w'' => ''abc'') ), ''c'' => null); $key = ''b.x.z''; $path = explode(''.'', $key); print_r(Arrays::getNestedValue($arr, $path));

Del mismo modo, si necesita establecer un valor anidado, puede usar el método Arrays::setNestedValue .

$arr = array(''a'' => 1, ''b'' => array( ''y'' => 2, ''x'' => array(''z'' => 5, ''w'' => ''abc'') ), ''c'' => null); Arrays::setNestedValue($arr, array(''d'', ''e'', ''f''), ''value''); print_r($arr);


Si las claves de la matriz son únicas, puede resolver el problema en unas pocas líneas de código usando array_walk_recursive :

$arr = array(''a'' => 1, ''b'' => array( ''y'' => 2, ''x'' => array(''z'' => 5, ''w'' => ''abc'') ), ''c'' => null); function changeVal(&$v, $key, $mydata) { if($key == $mydata[0]) { $v = $mydata[1]; } } $key = ''z''; $value = ''56''; array_walk_recursive($arr, ''changeVal'', array($key, $value)); print_r($arr);


Suponiendo que $path ya es una matriz a través de explode (o agregar a la función), puede usar referencias. isset agregar alguna comprobación de errores en caso de $path no válido $path etc. (think isset ):

$key = ''b.x.z''; $path = explode(''.'', $key);

Adquiridor

function get($path, $array) { //$path = explode(''.'', $path); //if needed $temp =& $array; foreach($path as $key) { $temp =& $temp[$key]; } return $temp; } $value = get($path, $arr); //returns NULL if the path doesn''t exist

Setter / Creador

Esta combinación establecerá un valor en una matriz existente o creará la matriz si pasa una que aún no se ha definido. Asegúrese de definir $array para pasar por referencia &$array :

function set($path, &$array=array(), $value=null) { //$path = explode(''.'', $path); //if needed $temp =& $array; foreach($path as $key) { $temp =& $temp[$key]; } $temp = $value; } set($path, $arr); //or set($path, $arr, ''some value'');

Unsetter

Esto unset la clave final en la ruta:

function unsetter($path, &$array) { //$path = explode(''.'', $path); //if needed $temp =& $array; foreach($path as $key) { if(!is_array($temp[$key])) { unset($temp[$key]); } else { $temp =& $temp[$key]; } } } unsetter($path, $arr);

* La respuesta original tenía algunas funciones limitadas que dejaré en caso de que sean de utilidad para alguien:

Setter

Asegúrese de definir $array para pasar por referencia &$array :

function set(&$array, $path, $value) { //$path = explode(''.'', $path); //if needed $temp =& $array; foreach($path as $key) { $temp =& $temp[$key]; } $temp = $value; } set($arr, $path, ''some value'');

O si desea devolver la matriz actualizada (porque estoy aburrido):

function set($array, $path, $value) { //$path = explode(''.'', $path); //if needed $temp =& $array; foreach($path as $key) { $temp =& $temp[$key]; } $temp = $value; return $array; } $arr = set($arr, $path, ''some value'');

Creador

Si desea crear la matriz y, opcionalmente, establecer el valor:

function create($path, $value=null) { //$path = explode(''.'', $path); //if needed foreach(array_reverse($path) as $key) { $value = array($key => $value); } return $value; } $arr = create($path); //or $arr = create($path, ''some value'');

Por diversión

Construye y evalúa algo como $array[''b''][''x''][''z'']; dada una cadena bxz :

function get($array, $path) { //$path = explode(''.'', $path); //if needed $path = "[''" . implode("''][''", $path) . "'']"; eval("/$result = /$array{$path};"); return $result; }


Tengo una solución realmente simple y sucia (¡ realmente sucia! ¡NO la use si el valor de la clave no es confiable! ). Puede ser más eficiente que recorrer la matriz.

function array_get($key, $array) { return eval(''return $array["'' . str_replace(''.'', ''"]["'', $key) . ''"];''); } function array_set($key, &$array, $value=null) { eval(''$array["'' . str_replace(''.'', ''"]["'', $key) . ''"] = $value;''); }

Ambas funciones realizan una eval en un fragmento de código donde la clave se convierte en un elemento de la matriz como código PHP. Y devuelve o establece el valor de la matriz en la clave correspondiente.


Tengo una utilidad que uso regularmente que compartiré. La diferencia es que utiliza la notación de acceso a la matriz (por ejemplo, b[x][z] ) en lugar de la notación de puntos (por ejemplo, bxz ). Con la documentación y el código, se explica por sí mismo.

<?php class Utils { /** * Gets the value from input based on path. * Handles objects, arrays and scalars. Nesting can be mixed. * E.g.: $input->a->b->c = ''val'' or $input[''a''][''b''][''c''] = ''val'' will * return "val" with path "a[b][c]". * @see Utils::arrayParsePath * @param mixed $input * @param string $path * @param mixed $default Optional default value to return on failure (null) * @return NULL|mixed NULL on failure, or the value on success (which may also be NULL) */ public static function getValueByPath($input,$path,$default=null) { if ( !(isset($input) && (static::isIterable($input) || is_scalar($input))) ) { return $default; // null already or we can''t deal with this, return early } $pathArray = static::arrayParsePath($path); $last = &$input; foreach ( $pathArray as $key ) { if ( is_object($last) && property_exists($last,$key) ) { $last = &$last->$key; } else if ( (is_scalar($last) || is_array($last)) && isset($last[$key]) ) { $last = &$last[$key]; } else { return $default; } } return $last; } /** * Parses an array path like a[b][c] into a lookup array like array(''a'',''b'',''c'') * @param string $path * @return array */ public static function arrayParsePath($path) { preg_match_all(''///[([^[]*)]/'',$path,$matches); if ( isset($matches[1]) ) { $matches = $matches[1]; } else { $matches = array(); } preg_match(''/^([^[]+)/'',$path,$name); if ( isset($name[1]) ) { array_unshift($matches,$name[1]); } else { $matches = array(); } return $matches; } /** * Check if a value/object/something is iterable/traversable, * e.g. can it be run through a foreach? * Tests for a scalar array (is_array), an instance of Traversable, and * and instance of stdClass * @param mixed $value * @return boolean */ public static function isIterable($value) { return is_array($value) || $value instanceof Traversable || $value instanceof stdClass; } } $arr = array(''a'' => 1, ''b'' => array( ''y'' => 2, ''x'' => array(''z'' => 5, ''w'' => ''abc'') ), ''c'' => null); $key = ''b[x][z]''; var_dump(Utils::getValueByPath($arr,$key)); // int 5 ?>