← CodeClarityLab Home
Browse by Category
+ added · updated 7d
← Back to glossary

Iterator Pattern

quality PHP 5.0+ Intermediate
debt(d7/e5/b3/t5)
d7 Detectability Operational debt — how invisible misuse is to your safety net

Closest to 'only careful code review or runtime testing' (d7). The detection_hints indicate automated detection is 'no' and the code pattern — a custom collection class without Iterator interface forcing callers to use getItems() then foreach — requires a human reviewer to spot. PHPStan (the listed tool) can catch type mismatches but won't flag a missing Iterator implementation as a structural problem. The misuse silently works but carries hidden costs.

e5 Effort Remediation debt — work required to fix once spotted

Closest to 'touches multiple files / significant refactor in one component' (e5). The quick_fix describes implementing five Iterator interface methods (current, key, next, rewind, valid) or refactoring to a generator. However, callers using getItems()-then-foreach patterns may be spread across multiple files, and fixing rewind() bugs or switching from direct arrays to a proper Iterator requires updating both the collection class and potentially its consumers.

b3 Burden Structural debt — long-term weight of choosing wrong

Closest to 'localised tax' (b3). The pattern applies per collection class. Once implemented, it mostly affects that one component and its direct callers. It doesn't define the system's shape, but it does impose a small ongoing tax on maintainers who must understand the Iterator contract and remember rewind() semantics for each custom collection.

t5 Trap Cognitive debt — how counter-intuitive correct behaviour is

Closest to 'notable trap (a documented gotcha most devs eventually learn)' (t5). The misconception field confirms the primary trap: developers believe foreach makes the Iterator pattern unnecessary, missing that implementing the interface enables custom objects to participate in foreach. The common_mistakes reinforce this — rewind() not resetting state (second foreach yields nothing) and not using IteratorAggregate or generators when simpler are well-known but non-obvious gotchas.

About DEBT scoring →

Also Known As

iterator PHP Iterator interface traversal pattern

TL;DR

Provides a uniform way to traverse a collection without exposing its internal structure — the foundation of PHP's foreach and SPL iterators.

Explanation

The Iterator pattern defines traversal behaviour (current(), key(), next(), rewind(), valid()) separately from the collection, allowing the same collection to be traversed in multiple ways. PHP builds this into the language: foreach works on any class implementing Iterator or IteratorAggregate. SPL provides specialised iterators: ArrayIterator, RecursiveIteratorIterator, LimitIterator, FilterIterator, and AppendIterator. Custom iterators enable lazy evaluation — a DatabaseIterator fetches rows one at a time rather than loading all into memory. Generators (yield) provide a simpler alternative for most custom iteration needs.

Common Misconception

PHP's foreach already makes the iterator pattern unnecessary. Implementing the Iterator interface lets custom objects participate in foreach, generators provide lazy iteration for large datasets, and the pattern enables uniform traversal across different collection types.

Why It Matters

The Iterator pattern provides a standard traversal interface without exposing internal collection structure — clients iterate uniformly over arrays, database results, or file lines without knowing the source.

Common Mistakes

  • Loading an entire dataset into memory when a lazy iterator would do — a database cursor or generator is more efficient.
  • Not implementing rewind() correctly — a second foreach produces no results because the iterator is exhausted.
  • Implementing Iterator directly when PHP's IteratorAggregate is simpler for wrapping an existing traversable.
  • Not using yield in generators when implementing lazy sequences — generators are PHP's lightweight iterator.

Code Examples

✗ Vulnerable
// Loading 1M rows into memory instead of iterating lazily:
function getAllOrders(): array {
    return $this->db->query('SELECT * FROM orders')->fetchAll(); // Loads everything
}
foreach (getAllOrders() as $order) { /* processes one at a time but fetched all */ }
✓ Fixed
// Iterator provides sequential access without exposing internal structure
class UserCursor implements Iterator {
    private int \$position = 0;
    public function __construct(private array \$users) {}
    public function current(): User  { return \$this->users[\$this->position]; }
    public function key(): int       { return \$this->position; }
    public function next(): void     { \$this->position++; }
    public function rewind(): void   { \$this->position = 0; }
    public function valid(): bool    { return isset(\$this->users[\$this->position]); }
}

foreach (new UserCursor(\$users) as \$user) {
    \$user->notify(\$message);
}

// Generator alternative — memory efficient for large datasets:
function userStream(PDO \$pdo): \Generator {
    \$stmt = \$pdo->query('SELECT * FROM users');
    while (\$row = \$stmt->fetch()) yield \$row;
}

Added 15 Mar 2026
Edited 22 Mar 2026
Views 25
Rate this term
No ratings yet
🤖 AI Guestbook educational data only
| |
Last 30 days
0 pings F 2 pings S 1 ping S 0 pings M 0 pings T 0 pings W 0 pings T 0 pings F 2 pings S 0 pings S 0 pings M 0 pings T 0 pings W 2 pings T 0 pings F 2 pings S 0 pings S 0 pings M 0 pings T 0 pings W 0 pings T 0 pings F 1 ping S 0 pings S 0 pings M 0 pings T 0 pings W 0 pings T 0 pings F 2 pings S
Amazonbot 1
No pings yesterday
Amazonbot 9 Perplexity 4 Unknown AI 2 Ahrefs 2 ChatGPT 2 Majestic 1 Google 1
crawler 20 crawler_json 1
DEV INTEL Tools & Severity
🟢 Low ⚙ Fix effort: Medium
⚡ Quick Fix
Implement PHP's Iterator interface (current, key, next, rewind, valid) to make any custom collection work with foreach — or use a generator function which is simpler for most cases
📦 Applies To
PHP 5.0+ web cli queue-worker
🔗 Prerequisites
🔍 Detection Hints
Custom collection class without Iterator interface forcing callers to use getItems() then foreach; manual index tracking in collection methods
Auto-detectable: ✗ No phpstan
⚠ Related Problems
🤖 AI Agent
Confidence: Low False Positives: High ✗ Manual fix Fix: Medium Context: Class Tests: Update

✓ schema.org compliant