5.8.28 새기능 2 - 컬렉션에 병합, 교체 기능 추가 free

2019-07-11

5.8.28 버전에서 Support/Collection::mergeRecursive(), Support/Collection::replcace(), Support/Collection::replaceRecursive() 메소드가 추가됐다.


Support/Collection::mergeRecursive()


mergeRecursive()는 주어진 배열이나 컬렉션을 기존의 컬렉션과 합친다. 기존의 merge()는 같은 문자열 키가 있으면 덮어썼는데, mergeRecursive()는 같은 문자열 키의 값을 배열로 만든다.


$collection = collect(['product_id' => 1, 'price' => 100]);

$merged = $collection->mergeRecursive(['product_id' => 2, 'price' => 200, 'discount' => false]);

$merged->all();
// ['product_id' => [1, 2], 'price' => [100, 200], 'discount' => false]

PHP의 array_merge_recursive 기능을 컬렉션에 추가한 것이고 하니 array_merge_recursive에 익숙치 않은 사람은 다음의 array_merge_recursive 설명도 참고하자.


array_merge_recursive


array_merge_recursive는 하나 이상의 배열을 재귀적으로 합치는 기능이다. array_merge는 최상위 레벨 인덱스를 기준으로 합치고, 같은 인덱스가 있으면 덮어쓴다. 반면 array_merge_recursive는 더 낮은 수준의 인덱스까지 처리해준다.


$a = [
'server' => [
'php' => 7.3
],
'database' => 'mysql'
];

$b = [
'server' => [
'node.js' => [9, 10]
]
];

$array_merge_result = array_merge($a, $b);
// ['server' => ['node.js' => [9, 10]], 'database' => 'mysql']

$array_merge_recursive_result = array_merge_recursive($a, $b);
// ['server' => ['php' => 7.3, 'node.js' => [9, 10]], 'database' => 'mysql']

Support/Collection::replace()와 replaceRecursive()


replace()merge()와 비슷하지만, 문자열 키 뿐만 아니 숫자 인덱스도 지원한다.


$collection = collect(['Taylor', 'Abigail', 'James']);

$replaced = $collection->replace([1 => 'Victoria', 3 => 'Finn']);

$replaced->all();

// ['Taylor', 'Victoria', 'James', 'Finn']

replaceRecursive()mergeRecursive()와 마찬가지로 다차원 배열을 재귀적으로 처리해준다.


$collection = collect(['Taylor', 'Abigail', ['James', 'Victoria', 'Finn']]);

$replaced = $collection->replaceRecursive(['Charlie', 2 => [1 => 'King']]);
// $replaced = $collection->replace(['Charlie', 2 => [1 => 'King']]);

$replaced->all();

// ['Charlie', 'Abigail', ['James', 'King', 'Finn']]

replaceRecursive 대신 replace로 해보면 아래와 같이 다른 결과가 나온다.


$collection = collect(['Taylor', 'Abigail', ['James', 'Victoria', 'Finn']]);

// $replaced = $collection->replaceRecursive(['Charlie', 2 => [1 => 'King']]);
$replaced = $collection->replace(['Charlie', 2 => [1 => 'King']]);

$replaced->all();

// ['Charlie', 'Abigail', ['King']]

array_replace, array_replace_recursive


컬렉션에 새로 추가된 replace()replaceRecursive()도 PHP의 array_replacearray_replace_recursive를 컬렉션 메소드로 구현한 것이다.


php.net의 예제를 보면 둘의 동작과 차이가 쉽게 이해가 될 것이다.


$base = ['citrus' => ["orange"] , 'berries' => ["blackberry", "raspberry"]];
$replacements = ['citrus' => ['pineapple'], 'berries' => ['blueberry']];

$basket = array_replace_recursive($base, $replacements);
print_r($basket);

$basket = array_replace($base, $replacements);
print_r($basket);

위 코드의 출력


Array
(
[citrus] => Array
(
[0] => pineapple
)

[berries] => Array
(
[0] => blueberry
[1] => raspberry
)

)
Array
(
[citrus] => Array
(
[0] => pineapple
)

[berries] => Array
(
[0] => blueberry
)

)

가십거리


PR을 보니 이미 같은 내용의 PR이 있었고 거절 당했었다. 혹시 코드가 이번 PR에 비해 구려서 채택이 안됐나 싶어 코드를 비교해봤는데, 완전히 같은 코드여서 의아했다. 지난번 PR을 리뷰했던 사람은 replace 대신 map을 활용할 것을 권유했었는데, 이번 PR을 제출한 사람은 map은 재귀적인 처리할 때는 오히려 문제가 될 수 있다고 댓글을 추가했다. 짐작컨데, 이전 PR 때는 리뷰어의 의견을 받아들여 거절했지만, 나중에 생각이 바뀐게 아닌가 싶다. 만약 그런거면 같은 내용의 코드로 먼저 PR 했던 사람이 약간 억울할 수 있을 것 같다.


===

1 1

2019년 7월 11




유료 구독자 전용 레터입니다.

한 달 1만원으로 매일 라라벨 관련 메일 받아보시고 과거 메일도 열람하세요. 일반 구독으로 공개글만 받아보실 수도 있습니다.

구독하기 버튼을 눌러주시면 구독과 동시에 xly에도 가입됩니다.

이현석

바쁜 팀장님 대신 알려주는 신입 PHP 개발자 안내서를 쓰고, 클린 아키텍처 인 PHP를 번역했습니다. 2020년에 출간될 Laravel Up & Running 2nd Edition을 번역하고 있습니다.