Trong PHP, iterable là một khái niệm quan trọng cho phép bạn lặp qua (iterate) một tập hợp các giá trị như mảng (array) hoặc đối tượng có thể lặp (traversable object). PHP cung cấp từ khóa iterable để chỉ định kiểu dữ liệu mà các giá trị có thể được lặp qua bằng các cấu trúc lặp như foreach.

Cụ thể, iterable là một kiểu dữ liệu có thể được sử dụng trong PHP từ phiên bản 7.1 trở đi và có thể bao gồm:

  • Mảng (array)
  • Đối tượng triển khai interface Traversable (ví dụ: Iterator, Generator)

Iterable giúp mã của bạn dễ đọc, linh hoạt hơn khi xử lý dữ liệu có thể được lặp qua, đồng thời cung cấp tính nhất quán trong việc định nghĩa kiểu dữ liệu có thể lặp lại.

1. Iterable là gì?

Iterable là một kiểu dữ liệu đặc biệt trong PHP đại diện cho bất kỳ thứ gì có thể được lặp qua. Nó bao gồm các loại dữ liệu phổ biến như:

  • Array (Mảng)
  • Đối tượng thực thi interface Traversable

Từ khóa iterable thường được sử dụng trong khai báo kiểu dữ liệu cho các tham số hoặc giá trị trả về của hàm, phương thức để đảm bảo rằng dữ liệu truyền vào có thể được lặp qua.

Cú pháp khai báo iterable

php
<?php

function iterateValues(iterable $items) {
    foreach ($items as $item) {
        echo $item . "\n";
    }
}

Trong ví dụ trên, tham số $items phải là một kiểu iterable (mảng hoặc đối tượng có thể lặp qua). Hàm iterateValues() sẽ lặp qua các phần tử và in chúng ra.

2. Ví dụ về Iterable với mảng

Khi sử dụng mảng (array) với iterable, PHP cho phép bạn lặp qua mảng như bình thường:

php
<?php

function printItems(iterable $items) {
    foreach ($items as $item) {
        echo $item . "\n";
    }
}

$values = [1, 2, 3, 4, 5];
printItems($values);

Kết quả:

shell
1
2
3
4
5

Giải thích:

  • Mảng $values được truyền vào hàm printItems() như một tham số kiểu iterable.
  • PHP cho phép bạn lặp qua mảng với cấu trúc foreach mà không gặp lỗi, vì mảng là một kiểu dữ liệu iterable.

3. Iterable với các đối tượng

Ngoài mảng, PHP cũng cho phép bạn sử dụng các đối tượng có thể lặp qua (các đối tượng triển khai interface Traversable, chẳng hạn như Iterator). Điều này giúp bạn linh hoạt hơn khi làm việc với dữ liệu có cấu trúc phức tạp.

Ví dụ với Iterator:

php
<?php

class NumberIterator implements Iterator
{
    private $numbers;
    private $position = 0;

    public function __construct($numbers) {
        $this->numbers = $numbers;
    }

    public function current() {
        return $this->numbers[$this->position];
    }

    public function key() {
        return $this->position;
    }

    public function next() {
        $this->position++;
    }

    public function rewind() {
        $this->position = 0;
    }

    public function valid() {
        return isset($this->numbers[$this->position]);
    }
}

function printIterable(iterable $items) {
    foreach ($items as $item) {
        echo $item . "\n";
    }
}

$iterator = new NumberIterator([10, 20, 30, 40]);
printIterable($iterator);

Kết quả:

shell
10
20
30
40

Giải thích:

  • NumberIterator là một class triển khai interface Iterator của PHP, cho phép đối tượng này trở thành iterable.
  • Phương thức printIterable() nhận một tham số kiểu iterable và có thể lặp qua cả mảng và các đối tượng triển khai Traversable.
  • Đối tượng $iterator chứa một tập hợp số và có thể được lặp qua giống như một mảng.

4. Sử dụng iterable với Generator

Generator là một cách khác để tạo ra các đối tượng có thể lặp qua trong PHP mà không cần tạo toàn bộ mảng hoặc danh sách trong bộ nhớ. Generators rất hữu ích khi bạn làm việc với các tập dữ liệu lớn vì chúng chỉ tính toán các giá trị theo nhu cầu (lazy evaluation).

Ví dụ về Generator:

php
<?php

function numberGenerator() : iterable {
    for ($i = 1; $i <= 5; $i++) {
        yield $i;
    }
}

function printIterable(iterable $items) {
    foreach ($items as $item) {
        echo $item . "\n";
    }
}

$numbers = numberGenerator();
printIterable($numbers);

Kết quả:

shell
1
2
3
4
5

Giải thích:

  • Hàm numberGenerator() trả về một Generator (một kiểu iterable).
  • Generator giúp tạo ra các phần tử một cách lười biếng (chỉ tính toán giá trị khi cần).
  • Hàm printIterable() có thể lặp qua generator giống như một mảng thông thường.

5. Kiểu trả về iterable

Ngoài việc sử dụng iterable cho tham số, bạn cũng có thể khai báo một hàm hoặc phương thức trả về kiểu iterable. Điều này cho phép phương thức hoặc hàm trả về mảng hoặc đối tượng có thể lặp.

Ví dụ:

php
<?php

function getIterableData(): iterable {
    return [100, 200, 300];
}

$items = getIterableData();
foreach ($items as $item) {
    echo $item . "\n";
}

Kết quả:

shell
100
200
300

Giải thích:

  • Hàm getIterableData() trả về một kiểu iterable, có thể là một mảng hoặc một đối tượng có thể lặp.
  • Dữ liệu trả về được sử dụng trong một vòng lặp foreach như một tập hợp có thể lặp lại.

6. Ưu điểm của iterable

  • Tính linh hoạt: iterable cho phép hàm hoặc phương thức của bạn chấp nhận hoặc trả về nhiều kiểu dữ liệu có thể lặp (mảng và đối tượng).
  • Tính nhất quán: Khi sử dụng iterable, bạn có thể đảm bảo rằng dữ liệu truyền vào hoặc trả về luôn có thể được lặp qua, giúp mã an toàn và dễ bảo trì hơn.
  • Giảm chi phí bộ nhớ: Bằng cách sử dụng các đối tượng như Generator, bạn có thể xử lý các tập dữ liệu lớn mà không phải tải tất cả dữ liệu vào bộ nhớ một lần.

7. Iterable với mảng và đối tượng kết hợp

Bạn cũng có thể truyền cả mảng và đối tượng vào một hàm hoặc phương thức sử dụng iterable, nhờ khả năng linh hoạt của kiểu iterable.

Ví dụ:

php
<?php

function combineIterable(iterable $items) {
    foreach ($items as $item) {
        echo $item . "\n";
    }
}

$array = [1, 2, 3];
$iterator = new ArrayIterator([4, 5, 6]);

combineIterable($array);
combineIterable($iterator);

Kết quả:

shell
1
2
3
4
5
6

Giải thích:

  • Hàm combineIterable() có thể nhận cả mảng và đối tượng có thể lặp (như ArrayIterator).
  • Bạn có thể sử dụng iterable để xử lý nhiều loại dữ liệu mà không cần phải thay đổi mã lặp.

Kết luận

Iterable trong PHP là một khái niệm quan trọng giúp bạn làm việc với dữ liệu có thể lặp qua một cách linh hoạt và hiệu quả. Bằng cách sử dụng từ khóa iterable, bạn có thể tạo các hàm và phương thức chấp nhận và trả về các tập dữ liệu mà có thể được lặp lại bằng foreach, cho dù đó là mảng, đối tượng triển khai Traversable, hay các generator.

Những ưu điểm chính của iterable bao gồm tính linh hoạt, dễ sử dụng, và giảm chi phí bộ nhớ khi làm việc với các tập dữ liệu lớn. Iterable đặc biệt hữu ích trong các dự án lớn hoặc khi bạn cần làm việc với nhiều loại dữ liệu khác nhau nhưng vẫn muốn duy trì mã nguồn sạch sẽ và có tính nhất quán.