時たま何かにデータを渡す時にキーをキャメルケースにする必要があります。この時オブジェクトや配列をまとめて操作して、そのキーやプロパティ名をキャメルケースにできると便利です。これを実現する関数を紹介します。
まず文字列をスネークケース、ケバブケースあるいは空白区切りからキャメルケースにする関数です。これは次のようにできます。
<?php
/**
* スネークケースやケバブケースをスネークケースに変換する
* @param string $string
* @return string
*/
function to_camel_case(string $string): string
{
// ケバブケースやスネークケースの区切りをスペースに変換
$string = str_replace(['-', '_'], ' ', $string);
// 各単語の最初の文字を大文字に変換
$string = ucwords($string);
// スペースを削除して結合
$string = str_replace(' ', '', $string);
// 最初の文字を小文字に変換
return lcfirst($string);
}
// テスト
echo to_camel_case('space string') . "\n"; // "spaceString"
echo to_camel_case('snake_case_string') . "\n"; // "snakeCaseString"
echo to_camel_case('kebab-case-string') . "\n"; // "kebabCaseString"
PHPには大文字小文字の変換を行う関数があります。これと区切り文字の制御を組み合わせることで文字列中の塊の最初だけ大文字にして詰める、といったことができます。
PHP: ucwords – Manual
PHP: lcfirst – Manual
次いで配列のキーを再帰的にキャメルケースにする関数です。これは配列の中を見てキーを先ほどのto_camel_caseで変え、配列が見つかったら更に奥に行き、再びto_camel_caseして…といった具合に処理します。
/**
* 配列のキーをキャメルケースに変換する
* @param array $array
* @return array
*/
function array_key_camel(array $array): array
{
// 引数で渡された配列を詰め替えるための変数
$results = [];
foreach($array as $key => $value) {
// 配列が見つかったら、再帰呼び出しをしてその配列のキーをキャメルケースに変換する
if(is_array($value)) {
$value = array_key_camel($value);
}
// キーをキャメルケースにして詰め替える
$results[to_camel_case($key)] = $value;
}
// キーがキャメルケースになった $array である $result を返す
return $results;
}
var_dump(array_key_camel(['snake_case_key' => 'value', 'nested_array' => ['nested_key' => 'nested_value']]));
//array(2) {
// ["snakeCaseKey"]=>
// string(5) "value"
// ["nestedArray"]=>
// array(1) {
// ["nestedKey"]=>
// string(12) "nested_value"
// }
//}
次いでオブジェクトです。次のコードでは元々設定されているスコープを尊重して public のものしか読み取れない様にしています。データの受け渡しのための変換が目的であればこれで十分です。もしprivateやprotectedのプロパティについても処理が必要ならばRefrectionを使う必要があります。
/**
* オブジェクトのキーをキャメルケースに変換する
* @param $object
* @return stdClass
*/
function object_key_camel($object): object
{
// stdClassに詰め替える。
// 元のクラスのインスタンスではなくなるので注意(どのみちプロパティ名が変わったらメソッドが動かなくなる)
$newObject = new stdClass();
// プロパティを列挙してループ
foreach(get_object_vars($object) as $key => $value) {
// オブジェクトが見つかったら、再帰呼び出しをしてそのオブジェクトのプロパティ名をキャメルケースに変換する
if(is_object($value)) {
$value = object_key_camel($value);
}
// プロパティ名をキャメルケースにして、PHPの可変プロパティ名の機能を使って詰め替える
$newObject->{to_camel_case($key)} = $value;
}
return $newObject;
}
class TestClass
{
public $publicProperty = 'public value';
protected $protectedProperty = 'protected value';
private $privateProperty = 'private value';
}
$testObject = new TestClass();
var_dump(object_key_camel($testObject));
//object(stdClass)#2 (1) {
// ["publicProperty"]=>
// string(12) "public value"
//}
$properties = get_object_vars($testObject);
$std = json_decode(json_encode([
'snake_case_key' => 'value',
'nested_obj' => ['nested_key' => 'nested_value']
]));
var_dump(object_key_camel($std));
//object(stdClass)#4 (2) {
// ["snakeCaseKey"]=>
// string(5) "value"
// ["nestedObj"]=>
// object(stdClass)#5 (1) {
// ["nestedKey"]=>
// string(12) "nested_value"
// }
//}
ここまでで文字列をキャメルケースにする関数、配列のキーを再帰的にキャメルケースにする関数、オブジェクトのプロパティ名を再帰的にキャメルケースにする関数が用意できました。これらのコードを組み合わてオブジェクトの中の配列、配列の中のオブジェクトについてもキャメルケース化ができます。これは次のようにできます。
/**
* 配列のキーまたはオブジェクトのプロパティ名を再帰的にキャメルケースに変換する
* @param object|array $input
* @return object|array
*/
function mixed_key_camel(object|array $input): object|array
{
if(is_array($input)) {
// 配列の場合
foreach($input as $key => $value) {
// 配列やオブジェクトの場合は再帰的に処理
if(is_array($value) || is_object($value)) {
$input[$key] = mixed_key_camel($value);
}
}
return array_key_camel($input);
} elseif(is_object($input)) {
// オブジェクトの場合
foreach(get_object_vars($input) as $key => $value) {
// 配列やオブジェクトの場合は再帰的に処理
if(is_array($value) || is_object($value)) {
$input->$key = mixed_key_camel($value);
}
}
return object_key_camel($input);
}
// 配列でもオブジェクトでもない場合はそのまま返す
return $input;
}
// 使用例
$complexData = [
'snake_array' => [
'nested_obj' => new TestClass(),
'another_key' => 'some value'
],
'simple_key' => 'example'
];
var_dump(mixed_key_camel($complexData));
//array(2) {
// ["snakeArray"]=>
// array(2) {
// ["nestedObj"]=>
// object(stdClass)#5 (1) {
// ["publicProperty"]=>
// string(12) "public value"
// }
// ["anotherKey"]=>
// string(10) "some value"
// }
// ["simpleKey"]=>
// string(7) "example"
//}
こんな感じで文字列をキャメルケースにできます。もしスネークケースやケバブケースパターンを作るのであれば、例のコードの中のto_camel_caseを適宜差し替えればOKです。プロジェクトのどこかしらでケースの不一致がありそれを調整する時にこういった関数があると便利です。