본문 바로가기

비개발자의 개발 일지

현장 팀장에서 수출 ERP까지 — AI와 함께 시스템을 만든 기록

시리즈 보기
php

PHP IteratorAggregate 인터페이스 완전 정리 — 객체 컬렉션을 foreach로 순회하는 방법

by 왕진 2026. 7. 13.
반응형

 

 

Web Development · PHP OOP

PHP IteratorAggregate 인터페이스 완전 정리

객체 컬렉션을 foreach로 순회할 수 있게 만드는 방법 — implements + ArrayIterator 패턴
시작 오늘 분석할 코드

Members 클래스는 Member 객체들을 배열에 담아 관리하는 컬렉션이다. PHP 내장 인터페이스 IteratorAggregate를 구현해서 foreach로 순회할 수 있게 만드는 패턴이다.

class Members implements IteratorAggregate { private $members = []; // Member 객체들을 담을 배열 public function add(Member $member) { $this->members[] = $member; // 배열 끝에 추가 } public function getIterator() { return new ArrayIterator($this->members); // $this->members 배열을 foreach로 순회할 수 있는 객체로 변환 } }
실제 출력 미리보기 (iterator.php에서 foreach 실행 시)
1 성1 이름1 email1@example.com password1
2 성2 이름2 email2@example.com password2
3 성3 이름3 email3@example.com password3
4 성4 이름4 email4@example.com password4
5 성5 이름5 email5@example.com password5

→ foreach가 getIterator()에서 반환된 ArrayIterator를 통해 Member 객체를 하나씩 꺼내 출력한다

용어 핵심 용어 정리
implements클래스가 인터페이스를 구현함을 선언. 요구하는 메서드를 반드시 작성해야 함
IteratorAggregatePHP 내장 인터페이스. getIterator() 구현을 요구하며, foreach 지원이 가능해짐
ArrayIteratorPHP 내장 클래스. 배열을 foreach로 순회할 수 있는 이터레이터 객체로 감싼다
getIterator()IteratorAggregate가 요구하는 메서드. foreach 실행 시 PHP 내부에서 자동 호출됨
컬렉션여러 객체를 모아 관리하는 객체. Members가 Member 객체들의 컬렉션 역할
타입 힌트add(Member $member)처럼 매개변수 타입 명시. 다른 타입 전달 시 TypeError 발생
이터레이터 패턴컬렉션 내부 구조를 노출하지 않고 순회 방법만 제공하는 디자인 패턴
$members[]배열 끝에 요소를 추가하는 PHP 문법. $array[] = $value 는 push와 동일
TraversablePHP가 foreach로 반복할 수 있음을 보장하는 내부 인터페이스. Iterator와 IteratorAggregate가 상속
컬렉션 패턴타입이 보장된 객체 그룹을 관리하는 OOP 설계. 배열에 아무 값이나 들어가는 문제를 방지

1 implements — 인터페이스 구현이란
PHP 내장 기능을 클래스에 "장착"하는 방법

implements IteratorAggregate는 "이 클래스는 IteratorAggregate 인터페이스를 구현하겠다"는 선언이다. PHP가 이 인터페이스에서 요구하는 getIterator() 메서드를 반드시 작성해야 한다. 작성하지 않으면 Fatal error가 발생한다. 대신 구현하면 PHP의 foreach가 이 객체를 순회할 수 있게 된다.

implements 없이 foreach 시도
foreach($members as $m)

Warning: 객체는 Traversable을 구현해야 foreach 가능. 배열이 아닌 객체는 직접 순회 불가.
implements IteratorAggregate
getIterator()가 호출되어 ArrayIterator 반환.
foreach가 이 이터레이터를 통해 Member 객체를 하나씩 꺼낸다.
※ PHP에서 기본 제공하는 인터페이스(Traversable, Countable, ArrayAccess 등)를 구현하면 내장 언어 기능과 연동된다.

2 add() 메서드 — 타입 힌트로 안전한 추가
add(Member $member) 에서 Member가 하는 역할

add(Member $member)Member는 타입 힌트다. 이 매개변수에는 반드시 Member 클래스의 객체만 전달해야 한다. 문자열이나 숫자 같은 다른 타입을 전달하면 PHP가 자동으로 TypeError를 발생시켜 잘못된 데이터가 컬렉션에 들어오는 것을 막는다.

public function add(Member $member) { $this->members[] = $member; // 배열 끝에 Member 객체 추가 } // 사용 예 $members->add($member1); // ✅ Member 객체 → 정상 $members->add("문자열"); // ❌ TypeError — Member 타입 아님
타입 힌트가 없으면 배열에 아무 값이나 들어갈 수 있어 나중에 foreach에서 예상치 못한 오류가 발생한다. 컬렉션 클래스에는 타입 힌트를 항상 명시하는 것이 좋다.

3 getIterator() — foreach의 작동 원리
foreach는 내부적으로 getIterator()를 호출한다

foreach($iterator as $member)를 실행하면 PHP는 먼저 $iteratorIteratorAggregate를 구현했는지 확인하고, 구현되어 있으면 getIterator()를 호출한다. 이 메서드가 반환한 ArrayIterator를 통해 배열 요소를 하나씩 꺼내며 반복 실행한다.

1
foreach 시작PHP가 대상 객체의 타입을 확인 → IteratorAggregate 구현 여부 체크
2
getIterator() 호출Members::getIterator() 실행 → new ArrayIterator($this->members) 반환
3
ArrayIterator가 순회배열 인덱스 0부터 순서대로 Member 객체를 $member 변수에 대입
4
반복 블록 실행$member->getId(), $member->getLastname() 등 출력
5
다음 요소로 이동ArrayIterator가 다음 인덱스로 이동. 마지막 요소까지 반복 후 종료
foreach 호출
getIterator()
ArrayIterator
$member 꺼냄
반복 출력

 

반응형

 

4 ArrayIterator — 배열을 이터레이터로 감싸는 이유
배열 자체가 아니라 ArrayIterator로 감싸야 하는 이유

getIterator()는 배열 그 자체가 아니라 new ArrayIterator($this->members)를 반환한다. 배열을 직접 반환하면 IteratorAggregate 인터페이스 계약을 어기게 되고(Traversable 객체가 아님), 추후 순회 방식을 커스텀 이터레이터로 교체하기도 어렵다.

// ❌ 배열 직접 반환 — 인터페이스 위반 (PHP 8.0+ Fatal error) public function getIterator() { return $this->members; // array 반환 — Traversable 아님 } // ✅ ArrayIterator로 감싸서 반환 — 올바른 방법 public function getIterator() { return new ArrayIterator($this->members); // Traversable 객체 반환 }
※ PHP 8.0+에서는 getIterator()의 반환 타입이 Traversable이어야 한다. ArrayIterator는 Traversable을 구현하고 있다.

5 PHP 8 반환 타입 선언 — 더 명확한 계약
PHP 8.0+에서 getIterator()에 반환 타입을 명시하는 방법

PHP 8.0부터 getIterator()에 반환 타입을 명시할 수 있다. Traversable을 반환 타입으로 선언하면 IDE와 정적 분석 도구가 타입 오류를 사전에 잡아준다. PHP 8.1에서는 더 구체적으로 ArrayIterator를 반환 타입으로 지정하는 것도 가능하다.

// PHP 7 방식 — 반환 타입 없음 public function getIterator() { return new ArrayIterator($this->members); } // PHP 8.0+ 권장 — Traversable 반환 타입 명시 public function getIterator(): Traversable { return new ArrayIterator($this->members); } // PHP 8.1+ — 더 구체적인 반환 타입 (ArrayIterator) public function getIterator(): ArrayIterator { return new ArrayIterator($this->members); }
반환 타입을 명시하면 잘못된 반환(배열 직접 반환 등)을 런타임이 아닌 정적 분석 단계에서 잡을 수 있다. 새 프로젝트에서는 명시를 권장.

6 전체 파일 연결 — 실제 사용 흐름
Member · Members · iterator.php 세 파일이 협력하는 방식

Members 클래스는 혼자 동작하지 않는다. Member(단일 객체) 클래스와 이를 조립하는 iterator.php가 함께 동작한다. 각 파일의 역할을 확인하자.

Member.php — 단일 멤버 데이터 객체
class Member { public function __construct( private int $id, private string $lastname, private string $firstname, private string $email, private string $password ) {} public function getId() { return $this->id; } public function getLastname() { return $this->lastname; } public function getFirstname() { return $this->firstname; } public function getEmail() { return $this->email; } public function getPassword() { return $this->password; } }
Members.php — 컬렉션 (오늘 분석 대상)
class Members implements IteratorAggregate { private $members = []; public function add(Member $member) { $this->members[] = $member; } public function getIterator() { return new ArrayIterator($this->members); } }
iterator.php — 조립 및 출력
$members = new Members(); for ($i = 1; $i <= 5; $i++) { $members->add(new Member( $i, "성{$i}", "이름{$i}", "email{$i}@example.com", "password{$i}" )); } foreach ($members->getIterator() as $member) { echo $member->getId() . ' ' . $member->getLastname() . ' ' . $member->getFirstname() . ' ' . $member->getEmail() . ' ' . $member->getPassword() . "<br>"; }

6 trait vs interface — 역할 비교
수평 확장의 두 가지 방식 — 언제 무엇을 쓰나

trait과 interface는 둘 다 클래스에 기능을 추가하는 수단이지만 목적이 다르다. trait은 "구현된 코드 재사용"이고, interface는 "타입 계약 + 기능 명세"다. IteratorAggregate처럼 PHP 내부와 연동해야 할 때는 interface를 구현하고, 여러 클래스에 공통 유틸 메서드를 배포할 때는 trait을 쓴다.

항목 trait interface
키워드 use implements
구현 포함 여부 ✅ 구현 코드 포함 ❌ 선언만 (구현 강제)
여러 개 동시 use A, B implements A, B
PHP 내장 연동 불가 ✅ foreach, count 등 내장 연동
직접 객체화 불가 불가
대표 사용처 로깅, 검증 유틸 재사용 IteratorAggregate, Countable

7 자주 하는 실수
실수 증상 해결
getIterator() 구현 누락 Fatal error: Class must implement method getIterator() implements IteratorAggregate 선언 시 getIterator() 반드시 작성
getIterator()에서 배열 직접 반환 return type must be Traversable 오류 new ArrayIterator($this->members) 로 감싸서 반환
add()에 Member 타입 외 값 전달 TypeError: Argument must be of type Member add() 호출 전 new Member()로 생성한 객체만 전달
$members로 직접 foreach Warning: Invalid argument for foreach foreach($members->getIterator() as $m) 로 이터레이터 명시 취득
Members 클래스를 배열처럼 $members[0] 접근 Undefined offset 오류 배열 접근은 ArrayAccess 인터페이스 별도 구현 필요. 또는 getter로 꺼냄

핵심 한 줄 요약

implements IteratorAggregatePHP 내장 인터페이스 구현 선언 — getIterator() 메서드 작성이 강제됨
getIterator()new ArrayIterator($this->members) 반환 — foreach가 내부적으로 이 메서드를 호출
ArrayIterator배열을 Traversable 객체로 감싸는 PHP 내장 클래스
타입 힌트 add(Member $m)Member 타입만 허용 — 잘못된 타입 전달 시 TypeError 자동 발생
trait vs interfacetrait=구현 재사용, interface=타입 계약. PHP 내장 기능 연동은 interface
컬렉션 패턴타입 힌트 + IteratorAggregate = 타입 안전한 객체 배열 관리

Tags

#PHP IteratorAggregate #ArrayIterator #implements #PHP 인터페이스 #foreach 객체 #PHP OOP #PHP 컬렉션 #이터레이터 패턴 #타입 힌트 #PHP 객체 배열 #PHP 객체지향 #웹개발 #티스토리
▼ 티스토리 태그 입력란 복사용
PHP IteratorAggregate, ArrayIterator, implements, PHP 인터페이스, foreach 객체, PHP OOP, PHP 컬렉션, 이터레이터 패턴, 타입 힌트, PHP 객체지향
반응형

댓글