어제 예고해드린대로 오늘은 라라벨 6에 추가된 레이지 컬렉션(Lazy Collection)을 소개해드리고자 합니다.
왜 쓰는가?
컬렉션이 있는데 왜 레이지 컬렉션이 나왔는지 알면 어떤 때 컬렉션을 쓰고 어떤 때 레이지 컬렉션을 쓸지 판단하는데 도움이 될 겁니다. 컬렉션은 배열을 쉽게 다루게 해주는 도구죠. 어제 살펴본 제너레이터의 핵심 용도는 적은 메모리로 대량의 데이터를 다루는 것이었습니다. 레이지 컬렉션의 핵심 용도도 컬렉션을 사용할 때 제너레이터를 활용하여 적은 메모리로 대량의 데이터를 다루는 것입니다.
레이지 컬렉션 만드는 방법
레이지 컬렉션 인스턴스를 직접 만들 땐 제너레이터 함수를 make() 매서드에 넘겨주면 됩니다.
$lazyCollection = LazyCollection::make(function(){
$handle = fopen('log.txt', 'r');
while (($line = fgets($handle)) !== false) {
yield $line;
}
})
참고로 컬렉션 인스턴스는 생성자에 배열을 넘겨서 만듭니다.
, 2, 3]);
레이지 컬렉션은 대부분의 컬렉션 매서드를 사용할 수 있습니다.
쿼리빌더 cursor()
데이터베이스 조회 결과를 레이지 컬렉션으로 만들어야 할 때는 cursor()를 쓰면 됩니다. 쿼리빌더의 cursor() 매서드가 제너레이터를 반환하는 대신 레이지 컬렉션을 반환하도록 변경되었습니다. 대량의 데이터를 적은 메모리로 처리하는 장점은 유지하면서 컬렉션 기능까지 사용할 수 있게 되었다고 보면 될 것 같습니다.

매서드
레이지 컬렉션은 컬렉션의 매서드를 대부분 사용할 수 있지만 컬렉션을 변경하는 매서드(예를 들어, shift: 컬렉션의 첫번째 아이템을 반환하고 컬렉션에서 제거, pop: 컬렉션의 마지막 아이템을 반환하고 제거, prepend: 컬렉션 앞에 아이템을 추가)는 사용할 수 없습니다. 제너레이터가 배열을 만들지 않고 개별 아이템을 처리하듯이 레이지 컬렉션은 컬렉션을 만들지 않고 순회하며 개별 아이템을 처리하지 않기 때문에 어찌보면 당연한 이야기네요.
반면 레이지 컬렉션에 추가된 매서드도 있습니다. tapEach()
인데요, each()
의 제너레이터 버전이라고 생각하시면 됩니다. each()
는 콜백 매서드를 즉시 실행하는 반면, tapEach
는 각 항목이 불려질 때 실행합니다.
마치며
아직 사용은 못해봤는데 빨리 써보고 싶네요. 운영 중인 웹사이트들이 대량의 데이터랄게 없는 서비스들이라 별 티는 안 날거 같은게 함정이지만요 ㅠ 나중에 써보고 이슈가 있으면 후기로 공유하겠습니다!
1일 1식 라라벨 52호
2019년 9월 11일