I am trying to convert the keys of a multi-dimensional array from CamelCase to snake_case, with the added complication that some keys have an exclamation mark that I\'d like rem
You can run a foreach on the arrays keys, this way you'll rename the keys in-place:
function transformKeys(&$array) {
foreach (array_keys($array) as $key) {
# This is what you actually want to do with your keys:
# - remove exclamation marks at the front
# - camelCase to snake_case
$transformedKey = ltrim($key, '!');
$transformedKey = strtolower($transformedKey[0] . preg_replace('/[A-Z]/', '_$0', substr($transformedKey, 1)));
# Store with new key
$array[$transformedKey] = &$array[$key];
unset($array[$key]);
# Work recursively
if (is_array($array[$transformedKey])) {
transformKeys($array[$transformedKey]);
}
}
}
Although this may not be an exact answer to the question, but I wanted to post it here for people who are searching for elegant solution for changing key case in multidimensional PHP arrays. You can also adapt it for changing array keys in general. Just call a different function instead of array_change_key_case_recursive
// converts all keys in a multidimensional array to lower or upper case
function array_change_key_case_recursive($arr, $case=CASE_LOWER)
{
return array_map(function($item)use($case){
if(is_array($item))
$item = array_change_key_case_recursive($item, $case);
return $item;
},array_change_key_case($arr, $case));
}
Create a function like:
function convertToCamelCase($array){
$finalArray = array();
foreach ($array as $key=>$value):
if(strpos($key, "_"))
$key = lcfirst(str_replace("_", "", ucwords($key, "_"))); //let's convert key into camelCase
if(!is_array($value))
$finalArray[$key] = $value;
else
$finalArray[$key] = $this->_convertToCamelCase($value );
endforeach;
return $finalArray;
}
and call this like:
$newArray = convertToCamelCase($array);
for working example see this
<?php
class Maison {
public $superficieAll_1;
public $addressBook;
}
class Address {
public $latitudeAmi;
public $longitude;
}
$maison = new Maison();
$maison->superficieAll_1 = 80;
$maison->addressBook->longitudeAmi = 2;
$maison->addressBook->latitude = 4;
$returnedArray = transformation($maison);
print_r($returnedArray);
function transformation($obj){
//object to array
$array = json_decode(json_encode((array) $obj),true);
//now transform all array keys
return transformKeys($array);
}
function transformKeys($array)
{
foreach ($array as $key => $value){
// echo "$key <br>";
unset($array[$key]);
$transformedKey = strtolower(preg_replace('/([a-z])([A-Z])/', '$1_$2', ltrim($key, '!')));
$array[$transformedKey] = $value;
// echo "$transformedKey update <br>";
if (is_array($value)) {
$array[$transformedKey] = transformKeys($value);
}
}
return $array;
}
This is the modified function I have used, taken from soulmerge's response:
function transformKeys(&$array)
{
foreach (array_keys($array) as $key):
# Working with references here to avoid copying the value,
# since you said your data is quite large.
$value = &$array[$key];
unset($array[$key]);
# This is what you actually want to do with your keys:
# - remove exclamation marks at the front
# - camelCase to snake_case
$transformedKey = strtolower(preg_replace('/([a-z])([A-Z])/', '$1_$2', ltrim($key, '!')));
# Work recursively
if (is_array($value)) transformKeys($value);
# Store with new key
$array[$transformedKey] = $value;
# Do not forget to unset references!
unset($value);
endforeach;
}
Here's a more generalized version of Aaron's. This way you can just plug the function you want to be operated on for all keys. I assumed a static class.
public static function toCamelCase ($string) {
$string_ = str_replace(' ', '', ucwords(str_replace('_',' ', $string)));
return lcfirst($string_);
}
public static function toUnderscore ($string) {
return strtolower(preg_replace('/([^A-Z])([A-Z])/', "$1_$2", $string));
}
// http://stackoverflow.com/a/1444929/632495
function transformKeys($transform, &$array) {
foreach (array_keys($array) as $key):
# Working with references here to avoid copying the value,
# since you said your data is quite large.
$value = &$array[$key];
unset($array[$key]);
# This is what you actually want to do with your keys:
# - remove exclamation marks at the front
# - camelCase to snake_case
$transformedKey = call_user_func($transform, $key);
# Work recursively
if (is_array($value)) self::transformKeys($transform, $value);
# Store with new key
$array[$transformedKey] = $value;
# Do not forget to unset references!
unset($value);
endforeach;
}
public static function keysToCamelCase ($array) {
self::transformKeys(['self', 'toCamelCase'], $array);
return $array;
}
public static function keysToUnderscore ($array) {
self::transformKeys(['self', 'toUnderscore'], $array);
return $array;
}