سی ام اس نویسسی ام اس نویسیاد بگیر، سیستم خودتو بنویس
مجلهتماس با ما
سی ام اس نویسسی ام اس نویس

CMS نویس مرجعی برای آموزش برنامه نویسی وب و PHP، توسعه افزونه‌های اختصاصی وردپرس، طراحی ورک‌فلو و اتوماسیون با n8n و توسعه CMS های اختصاصی است. هدف ما ارائه آموزش‌های کاربردی و راهکارهای حرفه‌ای برای توسعه‌دهندگان، کسب‌وکارها و علاقه‌مندان به دنیای برنامه‌نویسی است.

پیوندهای سریع
محصولات فیزیکیمحصولات دیجیتالدوره‌های آموزشی
سی ام اس نویس
مجله سی ام اس نویستماس با ماپنل کاربری
سی ام اس نویس — تمامی حقوق برای سی ام اس نویس محفوظ است. © 1406 تماس با ما09307711941
Iterator Pattern در PHP چیست؟ آموزش الگوی Iterator با مثال عملی

Iterator Pattern در PHP چیست؟ آموزش الگوی Iterator با مثال عملی

ممدیر کل سیستم ۲۲ شهریور ۱۴۰۵ ۱۹ دقیقه مطالعه ۲ بازدید
Iterator Pattern در PHP چیست؟ آموزش الگوی Iterator با مثال عملی

در بسیاری از پروژه‌های PHP با مجموعه‌ای از Objectها کار می‌کنیم.

برای مثال ممکن است یک سیستم فروشگاهی داشته باشیم که چندین محصول را نگهداری می‌کند:


Product 1

Product 2

Product 3

Product 4

...

یا یک سیستم مدیریت کتاب که مجموعه‌ای از کتاب‌ها را در اختیار ما قرار می‌دهد.

در حالت ساده، می‌توانیم یک آرایه داشته باشیم و با foreach روی آن حرکت کنیم:


foreach ($products as $product) {

    echo $product->getName();

}

اما همیشه اطلاعات ما به شکل یک آرایه ساده نیست.

گاهی Collection ما ساختار داخلی پیچیده‌ای دارد یا می‌خواهیم نحوه پیمایش داده‌ها را از ساختار اصلی Collection جدا کنیم.

اینجاست که Iterator Pattern کاربرد پیدا می‌کند.

Iterator یکی از الگوهای طراحی رفتاری است و هدف آن فراهم کردن امکان پیمایش ترتیبی عناصر یک Object یا Collection بدون وابستگی مستقیم به ساختار داخلی آن است. PHP نیز از طریق SPL رابط Iterator را برای پیاده‌سازی این قابلیت در اختیار برنامه‌نویس قرار می‌دهد.

در این مقاله از صفر یاد می‌گیریم Iterator Pattern چیست، چگونه در PHP آن را پیاده‌سازی کنیم و چه زمانی استفاده از آن منطقی است.


Iterator Pattern چیست؟

Iterator Pattern یک الگوی طراحی رفتاری است که روشی استاندارد برای دسترسی ترتیبی به عناصر یک مجموعه فراهم می‌کند، بدون اینکه کد استفاده‌کننده مجبور باشد از نحوه ذخیره‌سازی داخلی آن مجموعه اطلاع داشته باشد.

برای مثال فرض کنید کلاسی داریم:


class ProductCollection

{

    // ...

}

ممکن است داخل آن محصولات به شکل زیر ذخیره شده باشند:


private array $products;

اما کدی که می‌خواهد محصولات را پیمایش کند، نباید الزاماً بداند که محصولات دقیقاً در یک Array ذخیره شده‌اند.

هدف Iterator این است که بتوانیم چنین چیزی داشته باشیم:


foreach ($collection as $product) {

    // ...

}

بدون اینکه استفاده‌کننده درگیر جزئیات داخلی Collection شود.


# Iterator Pattern چه مشکلی را حل می‌کند؟

فرض کنید یک کلاس برای مدیریت کتاب‌ها داریم:


class BookCollection

{

    private array $books = [];



    public function add(Book $book): void

    {

        $this->books[] = $book;

    }



    public function getBooks(): array

    {

        return $this->books;

    }

}

حالا برای پیمایش کتاب‌ها می‌توانیم بنویسیم:


$collection = new BookCollection();



foreach ($collection->getBooks() as $book) {

    echo $book->getTitle();

}

در نگاه اول مشکلی وجود ندارد.

اما یک مشکل معماری داریم.

کد بیرونی مجبور شده بداند که BookCollection یک متد به نام:


getBooks()

دارد و این متد یک array برمی‌گرداند.

اگر بعداً نحوه ذخیره‌سازی کتاب‌ها را تغییر دهیم، ممکن است کدهای استفاده‌کننده نیز نیاز به تغییر داشته باشند.

Iterator یک لایه انتزاعی برای پیمایش ایجاد می‌کند.


# ساختار Iterator Pattern

ساختار کلی Iterator معمولاً شامل دو بخش مهم است:


Collection

    │

    │ creates/provides

    ↓

Iterator

    │

    ├── current()

    ├── key()

    ├── next()

    ├── rewind()

    └── valid()

Iterator مسئول نگهداری وضعیت پیمایش است و Collection مسئول نگهداری مجموعه داده‌هاست.

در PHP رابط استاندارد Iterator دقیقاً برای چنین سناریویی طراحی شده است.


# Iterator در PHP چیست؟

PHP یک Interface داخلی به نام:


Iterator

دارد.

برای پیاده‌سازی آن باید متدهای زیر را پیاده‌سازی کنیم:


current()

key()

next()

rewind()

valid()

یعنی ساختار کلی به این شکل است:


class MyIterator implements Iterator

{

    public function current(): mixed

    {

    }



    public function key(): mixed

    {

    }



    public function next(): void

    {

    }



    public function rewind(): void

    {

    }



    public function valid(): bool

    {

    }

}

این پنج متد، هسته اصلی Iterator در PHP هستند.


# متد current() در Iterator چیست؟

متد:


current()

عنصر فعلی Iterator را برمی‌گرداند.

مثلاً:


public function current(): Book

{

    return $this->books[$this->position];

}

اگر Iterator در موقعیت 0 باشد، اولین کتاب را برمی‌گرداند.

اگر در موقعیت 1 باشد، کتاب دوم را برمی‌گرداند.


# متد key() در Iterator چیست؟

متد:


key()

کلید یا موقعیت فعلی Iterator را برمی‌گرداند.

مثلاً:


public function key(): int

{

    return $this->position;

}

اگر Iterator روی عنصر سوم باشد، ممکن است مقدار زیر را برگرداند:


2

زیرا Array در PHP معمولاً از index صفر شروع می‌شود.


# متد next() در Iterator چیست؟

متد:


next()

Iterator را به عنصر بعدی منتقل می‌کند.

مثلاً:


public function next(): void

{

    $this->position++;

}

اگر موقعیت فعلی:


0

باشد، بعد از اجرای:


next();

به:


1

می‌رسد.


# متد rewind() در Iterator چیست؟

متد:


rewind()

Iterator را به ابتدای مجموعه برمی‌گرداند.

مثلاً:


public function rewind(): void

{

    $this->position = 0;

}

این متد برای شروع یا شروع مجدد پیمایش استفاده می‌شود.


# متد valid() در Iterator چیست؟

متد:


valid()

بررسی می‌کند که آیا موقعیت فعلی معتبر است یا خیر.

مثلاً:


public function valid(): bool

{

    return isset($this->books[$this->position]);

}

اگر هنوز عنصر دیگری وجود داشته باشد:


true

برگردانده می‌شود.

اگر به انتهای مجموعه رسیده باشیم:


false

برگردانده می‌شود.

foreach از همین مکانیزم برای تشخیص پایان پیمایش استفاده می‌کند.


# پیاده‌سازی کامل Iterator Pattern در PHP

حالا یک مثال واقعی ایجاد کنیم.

فرض کنید می‌خواهیم یک Collection برای کتاب‌ها بسازیم.

ابتدا کلاس Book را ایجاد می‌کنیم:


<?php



class Book

{

    public function __construct(

        private string $title,

        private string $author

    ) {

    }



    public function getTitle(): string

    {

        return $this->title;

    }



    public function getAuthor(): string

    {

        return $this->author;

    }

}

این کلاس فقط اطلاعات یک کتاب را نگهداری می‌کند.


# ساخت BookCollection

حالا Collection را ایجاد می‌کنیم:


<?php



class BookCollection

{

    private array $books = [];



    public function add(Book $book): void

    {

        $this->books[] = $book;

    }

}

در اینجا کتاب‌ها داخل:


private array $books = [];

ذخیره می‌شوند.


# ساخت Iterator سفارشی

حالا باید Iterator مخصوص BookCollection را ایجاد کنیم:


<?php



class BookIterator implements Iterator

{

    private int $position = 0;



    public function __construct(

        private array $books

    ) {

    }



    public function current(): Book

    {

        return $this->books[$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->books[$this->position]);

    }

}

حالا Iterator ما دقیقاً می‌داند چگونه بین کتاب‌ها حرکت کند.

این ساختار با نمونه‌های مستندشده برای DesignPatternsPHP نیز هم‌راستا است؛ در آن نمونه نیز Iterator موقعیت فعلی را نگه می‌دارد و متدهای current, key, next, rewind و valid را پیاده‌سازی می‌کند.


# اضافه کردن Iterator به Collection

حالا باید Collection بتواند Iterator خودش را ارائه کند.

کلاس را به شکل زیر تغییر می‌دهیم:


<?php



class BookCollection

{

    private array $books = [];



    public function add(Book $book): void

    {

        $this->books[] = $book;

    }



    public function getIterator(): BookIterator

    {

        return new BookIterator($this->books);

    }

}

اکنون می‌توانیم بنویسیم:


$collection = new BookCollection();



$collection->add(

    new Book('Clean Code', 'Robert C. Martin')

);



$collection->add(

    new Book('Design Patterns', 'Erich Gamma')

);



$collection->add(

    new Book('Learning PHP', 'John Doe')

);

و Iterator را دریافت کنیم:


$iterator = $collection->getIterator();


# استفاده مستقیم از Iterator

می‌توانیم Iterator را مستقیماً کنترل کنیم:


$iterator->rewind();



while ($iterator->valid()) {



    $book = $iterator->current();



    echo $book->getTitle();

    echo PHP_EOL;



    $iterator->next();

}

در هر مرحله:


rewind()

   ↓

valid()

   ↓

current()

   ↓

next()

   ↓

valid()

   ↓

...

این دقیقاً همان فرآیندی است که باعث می‌شود Iterator بتواند مجموعه را به صورت ترتیبی پیمایش کند.


# استفاده از Iterator با foreach

یکی از جذاب‌ترین بخش‌های Iterator در PHP این است که می‌توانیم Iterator را مستقیماً با foreach استفاده کنیم.

مثلاً:


$iterator = $collection->getIterator();



foreach ($iterator as $book) {

    echo $book->getTitle();

    echo PHP_EOL;

}

خروجی:


Clean Code

Design Patterns

Learning PHP

در این حالت دیگر نیازی نیست خودمان rewind()، valid()، current() و next() را به صورت دستی صدا بزنیم.

PHP این عملیات را هنگام اجرای foreach مدیریت می‌کند.

به همین دلیل یکی از کاربردهای مهم Iterator این است که یک Object را به شکلی ارائه کنیم که بتوان با آن مانند یک Collection قابل پیمایش رفتار کرد.


# پیاده‌سازی کامل مثال

برای درک بهتر، کل مثال را در یک فایل می‌توانیم به شکل زیر بنویسیم:


<?php



class Book

{

    public function __construct(

        private string $title,

        private string $author

    ) {

    }



    public function getTitle(): string

    {

        return $this->title;

    }



    public function getAuthor(): string

    {

        return $this->author;

    }

}



class BookIterator implements Iterator

{

    private int $position = 0;



    public function __construct(

        private array $books

    ) {

    }



    public function current(): Book

    {

        return $this->books[$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->books[$this->position]);

    }

}



class BookCollection

{

    private array $books = [];



    public function add(Book $book): void

    {

        $this->books[] = $book;

    }



    public function getIterator(): BookIterator

    {

        return new BookIterator($this->books);

    }

}



$collection = new BookCollection();



$collection->add(

    new Book('Clean Code', 'Robert C. Martin')

);



$collection->add(

    new Book('Design Patterns', 'Erich Gamma')

);



$collection->add(

    new Book('Learning PHP', 'John Doe')

);



foreach ($collection->getIterator() as $book) {

    echo $book->getTitle();

    echo ' - ';

    echo $book->getAuthor();

    echo PHP_EOL;

}

خروجی:


Clean Code - Robert C. Martin

Design Patterns - Erich Gamma

Learning PHP - John Doe


# چرا Iterator را مستقیماً داخل Collection قرار ندهیم؟

ممکن است بپرسید چرا متدهای زیر را مستقیماً داخل BookCollection قرار ندهیم؟


current()

next()

rewind()

valid()

از نظر فنی می‌توان چنین کاری کرد، اما بهتر است مسئولیت‌ها را جدا کنیم.

BookCollection مسئول نگهداری کتاب‌هاست.

در مقابل:

BookIterator مسئول پیمایش کتاب‌هاست.

بنابراین:


BookCollection

    ↓

نگهداری داده‌ها



BookIterator

    ↓

پیمایش داده‌ها

این جداسازی باعث می‌شود Collection و منطق پیمایش آن از یکدیگر مستقل‌تر باشند.


# IteratorAggregate در PHP چیست؟

PHP علاوه بر Iterator، Interface دیگری به نام:


IteratorAggregate

دارد.

در بسیاری از پروژه‌ها، استفاده از IteratorAggregate ساده‌تر است.

این Interface به جای اینکه مجبور باشیم تمام متدهای Iterator را در خود Collection پیاده‌سازی کنیم، به ما اجازه می‌دهد یک Iterator را از طریق متد:


getIterator()

برگردانیم.

ساختار ساده آن:


class BookCollection implements IteratorAggregate

{

    private array $books = [];



    public function getIterator(): Traversable

    {

        return new ArrayIterator($this->books);

    }

}

حالا می‌توانیم مستقیماً بنویسیم:


foreach ($collection as $book) {

    echo $book->getTitle();

}


# IteratorAggregate یا Iterator؟

این دو Interface را نباید با یکدیگر اشتباه بگیریم.

Iterator

وقتی می‌خواهیم خودمان کنترل کامل پیمایش را داشته باشیم، معمولاً از:


Iterator

استفاده می‌کنیم.

در این حالت باید متدهایی مانند:


current()

key()

next()

rewind()

valid()

را پیاده‌سازی کنیم.

IteratorAggregate

اگر Collection فقط می‌خواهد یک Iterator برای پیمایش ارائه کند، IteratorAggregate معمولاً ساده‌تر است.

مثلاً:


class ProductCollection implements IteratorAggregate

{

    private array $products = [];



    public function getIterator(): Traversable

    {

        return new ArrayIterator($this->products);

    }

}

در این حالت منطق پیمایش توسط ArrayIterator انجام می‌شود.


# استفاده از Countable در کنار Iterator

گاهی علاوه بر پیمایش، می‌خواهیم بتوانیم تعداد عناصر Collection را نیز با count() دریافت کنیم.

برای این کار می‌توانیم از:


Countable

استفاده کنیم.

مثلاً:


class BookCollection implements IteratorAggregate, Countable

{

    private array $books = [];



    public function add(Book $book): void

    {

        $this->books[] = $book;

    }



    public function getIterator(): Traversable

    {

        return new ArrayIterator($this->books);

    }



    public function count(): int

    {

        return count($this->books);

    }

}

حالا:


echo count($collection);

تعداد کتاب‌ها را برمی‌گرداند.

ترکیب Iterator یا IteratorAggregate با Countable برای Collectionهای سفارشی در PHP کاربرد زیادی دارد و نمونه‌های DesignPatternsPHP نیز از Countable در کنار Iterator استفاده می‌کنند.


# Iterator Pattern در Laravel

در Laravel نیز با Collectionها بسیار زیاد کار می‌کنیم.

برای مثال:


$products = Product::query()

    ->where('active', true)

    ->get();

سپس:


foreach ($products as $product) {

    echo $product->name;

}

در اینجا توسعه‌دهنده معمولاً لازم نیست درگیر نحوه داخلی پیمایش Collection شود.

اگر در یک پروژه Laravel یک ساختار Collection اختصاصی داشته باشیم، می‌توانیم آن را با IteratorAggregate یا Iterator قابل پیمایش کنیم.

برای مثال:


class ProductCollection implements IteratorAggregate

{

    public function __construct(

        private array $products

    ) {

    }



    public function getIterator(): Traversable

    {

        return new ArrayIterator($this->products);

    }

}

حالا:


$products = new ProductCollection([

    new Product('Laptop'),

    new Product('Mouse'),

    new Product('Keyboard'),

]);



foreach ($products as $product) {

    echo $product->getName();

}

این روش زمانی مفید است که در پروژه Laravel خود Collectionهای Domain-specific یا ساختارهای سفارشی ایجاد کرده باشید.


# یک کاربرد واقعی: خواندن فایل CSV

یکی از مثال‌های مناسب برای Iterator، خواندن فایل‌ها به صورت ترتیبی است.

فرض کنید یک فایل CSV بزرگ داریم.

به جای اینکه کل اطلاعات را به صورت یکجا پردازش کنیم، می‌توانیم ردیف‌ها را یکی‌یکی پیمایش کنیم.

برای مثال:


foreach ($csvIterator as $row) {

    // پردازش یک ردیف

}

Iterator برای چنین سناریوهایی مناسب است، چون می‌تواند دسترسی ترتیبی به داده‌ها را فراهم کند. نمونه‌های آموزشی Iterator در PHP نیز پردازش فایل CSV را به عنوان یک کاربرد واقعی نشان می‌دهند.


# Iterator و مدیریت داده‌های زیاد

فرض کنید یک فایل دارای:


1,000,000 rows

است.

اگر تمام اطلاعات را همزمان در حافظه قرار دهیم، ممکن است مصرف RAM افزایش پیدا کند.

در بسیاری از سناریوها بهتر است داده‌ها را به صورت مرحله‌ای پردازش کنیم.

برای مثال:


Read row

   ↓

Process row

   ↓

Read next row

   ↓

Process row

   ↓

...

Iterator می‌تواند چنین مدل پیمایشی را امکان‌پذیر کند.

البته صرف استفاده از Iterator تضمین نمی‌کند که همیشه مصرف حافظه کم باشد؛ پیاده‌سازی Iterator باید واقعاً داده‌ها را به شکل مناسب و ترجیحاً تدریجی تولید کند.


# تفاوت Iterator Pattern و foreach

این دو مفهوم یکی نیستند.

foreach یک ساختار زبانی در PHP است.

اما Iterator یک مکانیزم و قرارداد برای تعریف نحوه پیمایش Objectهاست.

یعنی می‌توانیم Iterator را ایجاد کنیم و سپس از:


foreach

برای استفاده راحت‌تر از آن بهره ببریم.

به صورت ساده:


Iterator

    ↓

تعریف نحوه پیمایش



foreach

    ↓

استفاده راحت از پیمایش


# تفاوت Iterator و Collection

Collection مسئول نگهداری مجموعه است.

Iterator مسئول پیمایش مجموعه است.

مثلاً:


BookCollection

    ↓

کتاب‌ها را نگهداری می‌کند



BookIterator

    ↓

روی کتاب‌ها حرکت می‌کند

این جداسازی یکی از مهم‌ترین مفاهیم Iterator Pattern است.


# تفاوت Iterator و Visitor

در مقاله قبلی درباره Visitor Pattern صحبت کردیم.

این دو Pattern هدف کاملاً متفاوتی دارند.

Iterator

برای پیمایش عناصر استفاده می‌شود:


Collection

    ↓

Iterator

    ↓

Element 1

Element 2

Element 3

Visitor

برای اجرای عملیات مختلف روی Objectها استفاده می‌شود:


Element

    ↓

Visitor

    ↓

Operation

بنابراین:


Iterator → چگونه روی عناصر حرکت کنیم؟



Visitor → چه عملیاتی روی عناصر انجام دهیم؟

گاهی حتی می‌توان این دو Pattern را در یک پروژه با یکدیگر ترکیب کرد.


# مزایای Iterator Pattern

Iterator چند مزیت مهم دارد.

1. مخفی کردن ساختار داخلی Collection

کدی که Collection را مصرف می‌کند لازم نیست بداند اطلاعات دقیقاً چگونه ذخیره شده‌اند.


2. ایجاد Interface استاندارد برای پیمایش

به جای ساخت روش‌های متفاوت برای پیمایش Collectionهای مختلف، می‌توانیم از قراردادهای استاندارد PHP استفاده کنیم.


3. جداسازی مسئولیت‌ها

Collection مسئول داده است و Iterator مسئول پیمایش.


4. امکان ساخت پیمایش‌های سفارشی

می‌توان Iteratorهایی برای سناریوهای مختلف ساخت.

مثلاً:


ForwardIterator

ReverseIterator

FilteredIterator

TreeIterator

PaginatedIterator

برای مثال می‌توان Iteratorی ایجاد کرد که فقط محصولات فعال را برگرداند.


5. سازگاری با foreach

یکی از مهم‌ترین مزایای Iterator در PHP این است که می‌توان Objectهای سفارشی را به شکلی طراحی کرد که با foreach قابل پیمایش باشند.


# معایب Iterator Pattern

Iterator نیز مانند هر Design Pattern دیگری همیشه بهترین انتخاب نیست.

1. افزایش تعداد کلاس‌ها

ممکن است برای Collection و Iterator کلاس‌های جداگانه داشته باشیم.

در پروژه‌های بسیار ساده این موضوع می‌تواند پیچیدگی غیرضروری ایجاد کند.


2. احتمال پیچیده شدن منطق پیمایش

اگر Iterator رفتارهای پیچیده‌ای داشته باشد، نگهداری آن می‌تواند دشوار شود.


3. Iterator بد می‌تواند حافظه زیادی مصرف کند

اگر تمام داده‌ها قبل از پیمایش داخل حافظه ساخته شوند، صرف استفاده از Interface Iterator الزاماً باعث کاهش مصرف حافظه نمی‌شود.


# چه زمانی از Iterator Pattern استفاده کنیم؟

Iterator انتخاب خوبی است وقتی:

  • یک Object شامل مجموعه‌ای از Objectهای دیگر است.
  • می‌خواهید Object شما با foreach قابل پیمایش باشد.
  • نمی‌خواهید ساختار داخلی Collection را در اختیار مصرف‌کننده قرار دهید.
  • نیاز به الگوریتم پیمایش سفارشی دارید.
  • می‌خواهید منطق پیمایش از Collection جدا باشد.
  • داده‌ها ساختار پیچیده‌ای دارند.
  • نیاز دارید چند روش پیمایش متفاوت ایجاد کنید.

# چه زمانی از Iterator استفاده نکنیم؟

اگر فقط یک Array ساده دارید:


$products = [

    $product1,

    $product2,

    $product3,

];

معمولاً نیازی نیست فقط برای پیمایش آن یک Iterator سفارشی بسازید.

می‌توانید مستقیماً از:


foreach ($products as $product) {

    // ...

}

استفاده کنید.

Design Pattern زمانی ارزشمند است که یک مشکل واقعی معماری یا طراحی را حل کند، نه اینکه صرفاً برای استفاده از یک Pattern به پروژه اضافه شود. مستندات DesignPatternsPHP نیز تأکید می‌کند که مهم‌تر از شناخت Patternها، دانستن زمان مناسب استفاده از آن‌ها و توجه به trade-offهای هر Pattern است.


# تست Iterator با PHPUnit

می‌توانیم Iterator خود را با PHPUnit تست کنیم.

مثلاً:


<?php



use PHPUnit\Framework\TestCase;



class BookIteratorTest extends TestCase

{

    public function testCanIterateOverBooks(): void

    {

        $books = [

            new Book('Clean Code', 'Robert C. Martin'),

            new Book('Design Patterns', 'Erich Gamma'),

        ];



        $iterator = new BookIterator($books);



        $result = [];



        foreach ($iterator as $book) {

            $result[] = $book->getTitle();

        }



        $this->assertSame(

            [

                'Clean Code',

                'Design Patterns',

            ],

            $result

        );

    }

}

در این تست بررسی می‌کنیم که Iterator بتواند تمام کتاب‌ها را به ترتیب صحیح پیمایش کند.

نمونه‌های DesignPatternsPHP نیز برای Iterator تستی دارد که Collection را با foreach پیمایش کرده و نتیجه را بررسی می‌کند.


# اشتباهات رایج در پیاده‌سازی Iterator

اشتباه اول: فراموش کردن rewind()

اگر Iterator در ابتدای پیمایش به موقعیت صحیح منتقل نشود، ممکن است رفتار غیرمنتظره‌ای ایجاد شود.


اشتباه دوم: پیاده‌سازی نادرست valid()

مثلاً اگر همیشه:


return true;

برگردانیم، پیمایش ممکن است هیچ‌وقت به شکل صحیح پایان پیدا نکند.

valid() باید مشخص کند که آیا عنصر فعلی وجود دارد یا خیر.


اشتباه سوم: افزایش ندادن position

در next() باید موقعیت پیمایش تغییر کند:


public function next(): void

{

    $this->position++;

}

در غیر این صورت Iterator ممکن است روی یک عنصر باقی بماند.


اشتباه چهارم: استفاده از Iterator برای یک Array ساده

اگر فقط نیاز به پیمایش یک Array معمولی دارید، ساخت Iterator سفارشی معمولاً ضرورتی ندارد.


# Iterator Pattern در PHP به زبان ساده

اگر بخواهیم کل مقاله را در یک جمله خلاصه کنیم:

> Iterator Pattern به ما کمک می‌کند بدون درگیر شدن با ساختار داخلی یک مجموعه، عناصر آن را به صورت استاندارد و ترتیبی پیمایش کنیم.

ساختار کلی:


Collection

    │

    │

    ▼

Iterator

    │

    ├── rewind()

    ├── valid()

    ├── current()

    ├── key()

    └── next()

در PHP نیز Interface داخلی Iterator همین قرارداد اصلی را در اختیار ما قرار می‌دهد.

اگر فقط با Arrayهای ساده کار می‌کنید، احتمالاً نیازی به پیاده‌سازی Iterator ندارید.

اما اگر یک Collection سفارشی، ساختار پیچیده، پیمایش خاص یا Object قابل استفاده با foreach دارید، Iterator می‌تواند طراحی کد را تمیزتر و قابل توسعه‌تر کند.


# سوالات متداول Iterator Pattern در PHP

Iterator Pattern در PHP چیست؟

Iterator Pattern یک الگوی طراحی رفتاری برای پیمایش ترتیبی عناصر یک Collection بدون وابستگی مستقیم به ساختار داخلی آن است.

Interface Iterator در PHP چه متدهایی دارد؟

رابط Iterator شامل متدهای:


current()

key()

next()

rewind()

valid()

است.

تفاوت Iterator و IteratorAggregate چیست؟

در Iterator خود کلاس یا Iterator سفارشی منطق پیمایش را از طریق متدهای اصلی کنترل می‌کند.

در IteratorAggregate معمولاً متد getIterator() یک Iterator دیگر را برای پیمایش برمی‌گرداند.

آیا Iterator با foreach کار می‌کند؟

بله. Objectهایی که به شکل مناسب Iterator یا IteratorAggregate را پیاده‌سازی کنند می‌توانند با foreach پیمایش شوند.

آیا Iterator باعث کاهش مصرف RAM می‌شود؟

نه لزوماً. Iterator فقط مکانیزم پیمایش را فراهم می‌کند. کاهش مصرف حافظه زمانی اتفاق می‌افتد که داده‌ها نیز به صورت تدریجی و مناسب تولید یا خوانده شوند.

آیا Iterator Pattern در Laravel کاربرد دارد؟

بله. در ساخت Collectionهای سفارشی، پردازش داده‌ها، فایل‌های بزرگ، ساختارهای درختی و سناریوهایی که نیاز به پیمایش سفارشی دارند می‌توان از Iterator یا IteratorAggregate استفاده کرد.

نظرات (0)

نظرات پس از تأیید مدیر نمایش داده می‌شوند

هنوز نظری ثبت نشده است؛ اولین نفر باشید!

مقالات مرتبط

ساخت CMS با Laravel 12؛ آموزش ساخت سیستم مدیریت محتوا از صفر

ساخت CMS با Laravel 12؛ آموزش ساخت سیستم مدیریت محتوا از صفر

۲۴ دقیقه
ساخت فروشگاه اینترنتی با Laravel 12؛ آموزش پروژه‌محور از صفر تا طراحی هسته فروشگاه

ساخت فروشگاه اینترنتی با Laravel 12؛ آموزش پروژه‌محور از صفر تا طراحی هسته فروشگاه

۲۲ دقیقه
ساخت Marketplace با Laravel؛ آموزش طراحی فروشگاه چندفروشندگی

ساخت Marketplace با Laravel؛ آموزش طراحی فروشگاه چندفروشندگی

۲۲ دقیقه
مدیریت Queueهای سنگین در Laravel؛ آموزش پردازش کارهای طولانی

مدیریت Queueهای سنگین در Laravel؛ آموزش پردازش کارهای طولانی

۲۲ دقیقه