Hướng dẫn how important is the php iterator in an application? - trình lặp php quan trọng như thế nào trong một ứng dụng?

  • Nhà phát triển PHP hiện đại - Iterator
    • Lớp lặp đầu tiên của bạn
    • Tại sao lặp đi lặp lại?
    • SPL iterators
    • ArrayObject vs SPL ArrayIterator
    • Lặp lại hệ thống tệp
    • Nhìn trộm trước với bộ nhớ đệm
    • Máy phát điện
    • Kết thúc

Nếu bạn đã sử dụng một vòng lặp trong PHP, ý tưởng về việc lặp lại rất có thể không xa lạ với bạn. Bạn chuyển một mảng đến một vòng lặp và thực hiện một số logic bên trong vòng lặp, nhưng bạn có biết rằng bạn thực sự có thể truyền các cấu trúc dữ liệu khác ngoài các mảng cho một vòng lặp? Đó là nơi lặp đi vào chơi.

Dưới đây là định nghĩa tóm tắt của một trình lặp từ Wikipedia:

Trong lập trình máy tính, một trình lặp là một đối tượng cho phép một lập trình viên đi qua một thùng chứa, đặc biệt là danh sách. [...] Lưu ý rằng một trình lặp thực hiện truyền tải và cũng cho phép truy cập vào các phần tử dữ liệu trong một thùng chứa, nhưng không thực hiện lặp lại [. ..]. Một trình lặp có hành vi giống với con trỏ cơ sở dữ liệu.

Một số điểm chính cần nhớ ở đây:

  • Iterator cho phép chúng tôi đi qua một thùng chứa. Nó tương tự như các mảng.
  • Iterator không thực hiện lặp lại. Trong ví dụ trước của chúng tôi, cho việc lặp lại. Các loại vòng lặp khác như foreach và trong khi thực hiện lặp lại.

Bây giờ chúng ta biết định nghĩa của Iterator, khái niệm này vẫn có thể hơi mơ hồ, nhưng đừng lo lắng, chúng ta chưa hoàn thành. Bây giờ chúng tôi đã thiết lập rằng Iterator hoạt động tương tự như mảng và nó có thể được lặp qua trong một vòng lặp.

Thật hữu ích khi hiểu làm thế nào mảng thực sự hoạt động trong một vòng lặp. Hãy xem mã bên dưới:

$data = array(1,2,3,4);
for ($i=0; $i<count($data); $i++) {
    $key = $i;
    $value = $data[$i];
}

Đây là cách một mảng hoạt động trong một vòng lặp:

  • Trong bước 1, chúng tôi đặt $ i thành 0. ($ i = 0)
  • Trong bước 2, chúng tôi kiểm tra xem $ I nhỏ hơn độ dài của dữ liệu $. ($ i
  • Trong bước 3, chúng tôi tăng giá trị $ I lên 1. ($ i ++)
  • Trong bước 4, chúng ta có thể truy cập khóa của phần tử hiện tại. ($ key = $ i)
  • Trong bước 5, chúng ta cũng có thể nhận được giá trị của phần tử hiện tại. ($ value = $ data [$ i])

Chúng ta có thể trừu tượng các bước như các hàm đơn giản như dưới đây:

  • Bước 1 = tua lại ().
  • Bước 2 = hợp lệ ().
  • Bước 3 = Tiếp theo ().
  • Bước 4 = khóa ().
  • Bước 5 = Dòng điện ().

Ở cấp độ trừu tượng, chúng ta có thể tưởng tượng rằng, miễn là một đối tượng cung cấp năm hàm ở trên, nó có thể được lặp qua một vòng lặp.

Trong thực tế, một người lặp không có gì ngoài một lớp thực hiện tất cả năm bước được đề cập ở trên. Trong PHP, Thư viện PHP tiêu chuẩn (SPL), là một tập hợp các giao diện và các lớp nhằm giải quyết các vấn đề phổ biến, cung cấp giao diện vòng lặp tiêu chuẩn.

Iterator extends Traversable {
    /* Methods */
    abstract public mixed current ( void )
    abstract public scalar key ( void )
    abstract public void next ( void )
    abstract public void rewind ( void )
    abstract public boolean valid ( void )
}

Lớp lặp đầu tiên của bạn

Bây giờ chúng ta đã hiểu một người lặp là gì, đã đến lúc xây dựng cái đầu tiên của chúng ta.

Công cụ lặp đầu tiên của chúng tôi đại diện cho 10 kho hàng PHP nhìn chằm chằm hàng đầu từ GitHub. Chúng ta có thể truyền nó vào một foreach và lặp qua nó giống như một mảng. Chúng tôi sẽ đặt tên cho nó là xu hướng repositoryitorator.

Đầu tiên, chúng ta cần làm cho lớp của chúng ta thực hiện giao diện Iterator.

class TrendingRepositoriesIterator implements Iterator
{
    public function rewind()
    {
    }
 
    public function valid()
    {
    }
 
    public function next()
    {
    }
 
    public function key()
    {
    }
 
    public function current()
    {
    }
}

Một trình lặp phải luôn luôn thực hiện năm phương pháp được mô tả ở trên. Mã cuối cùng của xu hướng repositoryitoriesiter như sau:

?

class TrendingRepositoriesIterator implements Iterator
{
    private $repos = [];
    private $pointer = 0;
    public function __construct()
    {
        $this->populate();
    }
    public function rewind()
    {
        $this->pointer = 0;
    }
    public function valid()
    {
        return isset($this->repos[$this->pointer]);
    }
    public function next()
    {
        $this->pointer++;
    }
    public function key()
    {
        return $this->pointer;
    }
    public function current()
    {
        return $this->repos[$this->pointer];
    }
    private function populate()
    {
        $client = new GuzzleHttp\Client();
        $res = $client->request('GET', 'https://api.github.com/search/repositories', [ 'query' => ['q' => 'language:php', 'sort' => 'stars', 'order' => 'desc']]);
        $resInArray = json_decode($res->getBody(), true);
        $trendingRepos = array_slice($resInArray['items'], 0, 10);
        foreach ($trendingRepos as $rep) {
            $this->repos[] = $rep['name'];
        }
    }
}
  • Chức năng công cộng For (): Chúng tôi sẽ không đi sâu về chức năng này vì điều đó sẽ đánh bại mục đích của chương này. Về cơ bản, chức năng này lấy 10 kho hàng PHP hàng đầu từ GitHub thông qua API công khai GitHub và lưu trữ chúng vào thuộc tính $ Repos.
  • REPOS $ riêng: Chúng tôi sử dụng thuộc tính này để lưu trữ các kho lưu trữ.
  • Con trỏ $ riêng: Chúng tôi có thể sử dụng con trỏ bên trong của Array để thực hiện công việc, tuy nhiên vì chúng tôi đang xây dựng trình lặp của riêng mình, chúng tôi muốn giữ quyền kiểm soát hoàn toàn.
  • Hàm công khai CONSTRACT (): Thuộc tính tìm nạp các kho lưu trữ mục tiêu khi một đối tượng được khởi tạo.
  • Chức năng công khai tua lại (): Chúng ta có thể sử dụng điều này để đặt con trỏ lên vị trí đầu tiên.
  • Hàm công khai hợp lệ (): Miễn là giá trị của con trỏ hiện tại được đặt, nó là hợp lệ.
  • Chức năng công cộng Tiếp theo (): Điều này được sử dụng để tăng con trỏ lên 1 vị trí.
  • Hàm công khai hiện tại (): Chúng ta có thể trả về giá trị của con trỏ hiện tại thông qua hàm này.

Hãy xem trường hợp sử dụng của xu hướng repositoryitoriesitor, có thể được sử dụng giống như một mảng:

$trendingRepositoriesIterator = new TrendingRepositoriesIterator();
 
foreach ($trendingRepositoriesIterator as $repository) {
    echo $repository . "\n";
}
 
// Output
laravel
symfony
CodeIgniter
DesignPatternsPHP
Faker
yii2
composer
WordPress
sage
cakephp

Đáng kinh ngạc! Bây giờ chúng tôi đã viết trình lặp đầu tiên của chúng tôi và như bạn có thể thấy, nó thực sự rất dễ dàng và đơn giản.

Tại sao lặp đi lặp lại?

Bạn vẫn có thể tự hỏi tại sao chúng ta cần sử dụng Iterator. Chúng ta không thể sử dụng mảng? Câu trả lời là có hoặc không. Trong hầu hết các trường hợp, mảng là đủ cho công việc, mặc dù Iterator đi kèm với một số lợi thế chính, mà chúng tôi sẽ chia sẻ tiếp theo. Hãy nhớ rằng, chúng tôi không có nghĩa là đề xuất sử dụng Iterator trong mọi trường hợp.

Đóng gói

Trong trình lặp đầu tiên của chúng tôi, xu hướng repositoryitoriesiterator, các chi tiết của các kho lưu trữ github đi qua được hoàn thành ẩn từ bên ngoài. Chúng tôi có thể cập nhật cách chúng tôi lấy dữ liệu, nơi chúng tôi lấy dữ liệu từ và cách chúng tôi muốn đi qua các tài nguyên. Không cần thay đổi từ mã máy khách. Điều này, được gọi là đóng gói, là một trong những khái niệm chính của lập trình hướng đối tượng.

Các ví dụ bổ sung bao gồm:

Để lặp lại thông qua kết quả MySQL, chúng ta có thể sử dụng:

$result = mysql_query("SELECT * FROM books");
 
// Iterate over the structure
while ( $row = mysql_fetch_array($result) ) {
    // do stuff
}

Để lặp lại thông qua nội dung của tệp văn bản, chúng ta có thể:

$fh = fopen("books.txt", "r");
// Iterate over the structure
while (!feof($fh)) {
   $line = fgets($fh);
   // do stuff with the line here
}

Với Iterator, chúng ta có thể gói gọn quá trình đi qua sự truy đòi để thế giới bên ngoài không nhận thức được các hoạt động nội bộ. Trên thực tế, thế giới bên ngoài không cần phải biết nơi chúng ta lấy dữ liệu từ hoặc làm thế nào nó đi qua một vòng lặp. Tất cả những gì họ cần biết là, họ có thể lặp lại qua nó đơn giản như:

$bookIterator = new BookIterator();
foreach($bookIterator as $book) {
    // do stuff with $book
}

Đóng gói là một khái niệm rất mạnh mẽ và nó cho phép chúng tôi viết mã sạch.

Sử dụng bộ nhớ hiệu quả

Việc sử dụng bộ nhớ hiệu quả là một lợi ích chính của iterator.

Trong lớp TrendingRepositoryIeIterator của chúng tôi, chúng tôi thực sự có thể tìm nạp tài nguyên một cách linh hoạt, có nghĩa là chúng tôi sẽ chỉ tìm nạp dữ liệu từ API GitHub khi phương thức tiếp theo () được gọi. Kỹ thuật này được gọi là tải lười biếng. Nó giúp chúng tôi tiết kiệm một lượng bộ nhớ rất đáng kể vì giá trị chỉ được tạo ra khi cần thiết.

Dễ dàng thêm các chức năng bổ sung

Một lợi ích khác của việc sử dụng Iterator là chúng ta có thể trang trí nó để thêm các chức năng bổ sung. Lấy lớp TrendingRepositoryIterator của chúng tôi làm ví dụ. Chúng tôi muốn loại trừ "Laravel" khỏi tài nguyên. Một phương pháp rõ ràng là cập nhật lớp ban đầu của chúng tôi, mặc dù đó tất nhiên không phải là những gì chúng tôi sẽ làm ở đây.

Chúng ta có thể trang trí trình lặp gốc bằng cách sử dụng CallbackFilterIterator của SPL và không cần thay đổi nào cho TrendingRepositoryIterator.

$trendingRepositoriesIterator = new TrendingRepositoriesIterator();
    return $value != 'laravel';
});
foreach ($newTrendingRepositoriesIterator as $repository) {
    echo $repository . "\n";
}
// Output
symfony
CodeIgniter
DesignPatternsPHP
Faker
yii2
composer
WordPress
sage
cakephp

Phần thú vị của điều này là không có sự trùng lặp của các đối tượng. Các cuộc gọi lại chỉ bắn khi xu hướng repositoryitoriesIterator chạm vào phương thức tiếp theo (), và sau đó logic nó sẽ được áp dụng cho phù hợp. Đây là một cách tuyệt vời để lưu bộ nhớ cũng như tăng hiệu suất.

SPL iterators

Bây giờ chúng tôi hiểu được sức mạnh và lợi ích của việc sử dụng trình lặp, việc sử dụng các trình lặp lại là tốt để giải quyết các vấn đề phù hợp. Tuy nhiên, nếu chúng ta tự viết các trình lặp bất cứ khi nào chúng ta gặp phải một vấn đề mới, thì nó sẽ rất tốn thời gian vì nó yêu cầu chúng ta phải thực hiện một tập hợp các chức năng được xác định trước.

May mắn thay, PHP đã thực hiện một công việc tốt là cung cấp một bộ các phép lặp để giải quyết một số vấn đề phổ biến. Trong các phần sau, chúng tôi sẽ làm việc thông qua một tập hợp các trình lặp phổ biến được cung cấp bởi SPL. Là một phần còn lại, các tiêu chuẩn SPL cho thư viện PHP tiêu chuẩn đã được xây dựng để cung cấp một tập hợp các giao diện và các lớp nhằm giải quyết các vấn đề phổ biến.

ArrayObject vs SPL ArrayIterator

Trong PHP, mảng là một trong tám loại nguyên thủy. PHP cung cấp 79 chức năng để xử lý các nhiệm vụ liên quan đến mảng (tham chiếu). Nó hoàn toàn phù hợp để sử dụng mảng, tuy nhiên có những lúc, tùy thuộc vào mức độ bạn nắm lấy chương trình hướng đối tượng, mà bạn có thể muốn sử dụng mảng làm đối tượng. Trong trường hợp này, PHP cung cấp hai lớp để biến Array thành công dân hạng nhất trong mã hướng đối tượng.

ArrayObject

Tùy chọn đầu tiên chúng tôi có là ArrayObject. Lớp này cho phép các đối tượng hoạt động dưới dạng mảng.

Chúng ta hãy xem chữ ký lớp của nó:

ArrayObject implements IteratorAggregate , ArrayAccess , Serializable , Countable{
 ...
 public ArrayIterator getIterator ( void )
 ...
}

Như chúng ta đã thấy ở trên, ArrayObject thực hiện iteratoraggregate. Iteratoraggregate là gì? Nó là một giao diện để tạo ra một trình lặp bên ngoài. Nói một cách đơn giản, đó là một cách nhanh chóng để tạo trình lặp, thay vì thực hiện các giao diện iterator bằng năm phương thức: tua lại, hợp lệ, hiện tại, khóa và giá trị, Iteratoraggregate cho phép bạn giao nhiệm vụ đó cho một trình lặp khác. Tất cả những gì bạn cần làm là thực hiện một phương thức duy nhất ().

Iterator extends Traversable {
    /* Methods */
    abstract public mixed current ( void )
    abstract public scalar key ( void )
    abstract public void next ( void )
    abstract public void rewind ( void )
    abstract public boolean valid ( void )
}
0

ArrayObject thực hiện iteratoraggregate. Nó tạo ra một mảng hàng bên ngoài cho tính năng Iterator.

Khi ArrayObject thực hiện Iteratoraggregate, chúng ta có thể sử dụng nó trong một vòng lặp foreach chỉ là một mảng.

Iterator extends Traversable {
    /* Methods */
    abstract public mixed current ( void )
    abstract public scalar key ( void )
    abstract public void next ( void )
    abstract public void rewind ( void )
    abstract public boolean valid ( void )
}
1

Lý do chính chúng tôi muốn sử dụng ArrayObject là sử dụng Array theo kiểu hướng đối tượng.

Iterator extends Traversable {
    /* Methods */
    abstract public mixed current ( void )
    abstract public scalar key ( void )
    abstract public void next ( void )
    abstract public void rewind ( void )
    abstract public boolean valid ( void )
}
2

ArrayIterator

ArrayIterator hoạt động tương tự như ArrayObject.

Chúng ta hãy nhìn vào chữ ký lớp của nó là tốt:

Iterator extends Traversable {
    /* Methods */
    abstract public mixed current ( void )
    abstract public scalar key ( void )
    abstract public void next ( void )
    abstract public void rewind ( void )
    abstract public boolean valid ( void )
}
3

Nó gần như giống hệt với ArrayObject về các giao diện mà họ thực hiện. Sự khác biệt duy nhất là, thay vì giao diện ArrayIterator ARRAYObject thực hiện, nó thực hiện SeekableIterator.

Chúng tôi sử dụng ArrayIterator giống như cách chúng tôi sử dụng ArrayObject trong vòng lặp foreach:

Iterator extends Traversable {
    /* Methods */
    abstract public mixed current ( void )
    abstract public scalar key ( void )
    abstract public void next ( void )
    abstract public void rewind ( void )
    abstract public boolean valid ( void )
}
4

Sử dụng mảng theo kiểu hướng đối tượng:

Iterator extends Traversable {
    /* Methods */
    abstract public mixed current ( void )
    abstract public scalar key ( void )
    abstract public void next ( void )
    abstract public void rewind ( void )
    abstract public boolean valid ( void )
}
5

So sánh

Bạn có thể tự hỏi khi nào nên sử dụng ArrayObject và khi nào nên sử dụng ArrayIterator. Điều quan trọng là phải biết sự khác biệt và mối quan hệ giữa ArrayObject và ArrayIterator.

Như chúng ta đã phát hiện ra trong phần ArrayObject, ArrayObject thực sự tạo ra ArrayIterator làm trình lặp bên ngoài. Thật công bằng khi nói ArrayIterator thực hiện những gì ArrayObject làm, và nó cung cấp nhiều chức năng hơn, đặc biệt tìm kiếm một vị trí. Điều này được thực hiện bằng cách thực hiện SeekableIterator.

Bên cạnh việc di chuyển một con trỏ từ trên xuống dưới làm Iterator, nó cho phép bạn ngẫu nhiên nhảy đến một vị trí.

Iterator extends Traversable {
    /* Methods */
    abstract public mixed current ( void )
    abstract public scalar key ( void )
    abstract public void next ( void )
    abstract public void rewind ( void )
    abstract public boolean valid ( void )
}
6

Cuối cùng, ArrayIterator là một phần của SPL trong khi ArrayObject thì không.

Lặp lại hệ thống tệp

Đó là một nhiệm vụ rất phổ biến để liệt kê nội dung của một thư mục nhất định. PHP cung cấp rất nhiều chức năng để xử lý một hệ thống tệp. Một trong số đó là scandir ().

Giả sử chúng ta được giao một nhiệm vụ để liệt kê tất cả các tệp trong một thư mục nhất định như dưới đây:

Iterator extends Traversable {
    /* Methods */
    abstract public mixed current ( void )
    abstract public scalar key ( void )
    abstract public void next ( void )
    abstract public void rewind ( void )
    abstract public boolean valid ( void )
}
7

Chúng ta có thể thực hiện nó thông qua scandir () như hình dưới đây:

Iterator extends Traversable {
    /* Methods */
    abstract public mixed current ( void )
    abstract public scalar key ( void )
    abstract public void next ( void )
    abstract public void rewind ( void )
    abstract public boolean valid ( void )
}
8

Đây là hai thư mục ảo ("." Và "..") bạn sẽ tìm thấy trong mỗi thư mục của hệ thống tệp.

Vì chương này là về iterators, chúng tôi sẽ giới thiệu một số trình lặp để xử lý hệ thống tập tin. Hy vọng trong dự án tiếp theo của bạn, bạn sẽ có thể sử dụng một số trong số chúng. Ba lần lặp có ích: thư mục, fileSystemIterator và respuriveDirectoryIterator.

Trước khi chúng ta nhìn vào từng người trong số họ, thật hữu ích khi xem xét mối quan hệ thừa kế của họ:

Iterator extends Traversable {
    /* Methods */
    abstract public mixed current ( void )
    abstract public scalar key ( void )
    abstract public void next ( void )
    abstract public void rewind ( void )
    abstract public boolean valid ( void )
}
9

Thư mục

Lớp thư mục cung cấp một giao diện đơn giản để xem nội dung của các thư mục hệ thống tập tin.

Để hoàn thành cùng một nhiệm vụ, chúng ta có thể sử dụng thư mục:

class TrendingRepositoriesIterator implements Iterator
{
    public function rewind()
    {
    }
 
    public function valid()
    {
    }
 
    public function next()
    {
    }
 
    public function key()
    {
    }
 
    public function current()
    {
    }
}
0

Tham số duy nhất cần thiết để tạo đối tượng thư mục là đường dẫn của thư mục. So với hàm scandir, thay vì tên tệp dưới dạng chuỗi, thư mục return trả về một đối tượng. Đối tượng chứa nhiều thông tin khác nhau liên quan đến một tệp mà chúng ta có thể sử dụng.

FileSystemIterator

Để hoàn thành cùng một nhiệm vụ bằng cách sử dụng FileSystemIterator, chúng ta có thể sử dụng:

class TrendingRepositoriesIterator implements Iterator
{
    public function rewind()
    {
    }
 
    public function valid()
    {
    }
 
    public function next()
    {
    }
 
    public function key()
    {
    }
 
    public function current()
    {
    }
}
1

Điều này trông gần giống như thư mục, ngoại trừ việc FileSystemIterator đã tự động lọc ra hai thư mục ảo.

Họ có thực sự giống nhau không? Chúng ta có thể sử dụng một phương pháp đơn giản để nói sự khác biệt:

class TrendingRepositoriesIterator implements Iterator
{
    public function rewind()
    {
    }
 
    public function valid()
    {
    }
 
    public function next()
    {
    }
 
    public function key()
    {
    }
 
    public function current()
    {
    }
}
2

Kết quả của việc chạy trên tập lệnh từ CLI là:

class TrendingRepositoriesIterator implements Iterator
{
    public function rewind()
    {
    }
 
    public function valid()
    {
    }
 
    public function next()
    {
    }
 
    public function key()
    {
    }
 
    public function current()
    {
    }
}
3

Bây giờ chúng ta có thể thấy họ thực sự khá khác nhau trong nội bộ:

  • Thư mục trả về một số nguyên làm khóa và thư mục là giá trị trong một vòng lặp.
  • FileSystemIterator trả về một chuỗi đường dẫn đầy đủ làm khóa và đối tượng splfileinfo là giá trị trong một vòng lặp.

Trong thực tế, FileSystemIterator đi kèm với sự linh hoạt hơn một chút. Khi tạo đối tượng FileSystemIterator, nó chấp nhận đường dẫn của thư mục là tham số đầu tiên tương tự như thư mục. Hơn nữa, bạn có thể tùy chọn chuyển một tham số thứ hai dưới dạng cờ. Cờ này có thể định cấu hình các khía cạnh khác nhau của chức năng này.

  • FileSystemIterator :: current_as_pathname: Cờ này sẽ làm cho FileSystemIterator Return Path thay vì đối tượng SplfileInfo làm giá trị.

  • FileSystemIterator :: current_as_fileinfo: cờ này sẽ làm cho FileSystemIterator trả về đối tượng SplfileInfo làm giá trị. Đây là hành vi mặc định. Bạn không cần phải đặt nó một cách rõ ràng.

  • FileSystemIterator :: current_as_elf: cờ này sẽ làm cho fileSystemIterator return return fileSystemIterator chính nó làm giá trị.

  • FileSystemIterator :: key_as_pathname: Cờ này sẽ làm cho FileSystemIterator trả về đường dẫn tệp làm khóa. Đây là hành vi mặc định. Bạn không cần phải đặt nó một cách rõ ràng.

  • FileSystemIterator :: key_as_filename: Cờ này sẽ làm cho FileSystemIterator return Tên và tiện ích mở rộng thay vì đường dẫn tệp làm khóa.

  • FileSystemIterator :: Theo dõi_SymLinks: Cờ này sẽ làm cho respurfirectoryitoriterator :: haschildren () theo dõi các liên kết symlink.

  • FileSystemIterator :: new_civerse_and_key: cờ này giúp đặt hai cờ khác (FileSystemIterator :: key_as_filename và fileSystemIterator :: current_as_fileinfo) cùng một lúc.

  • FileSystemIterator :: SKIP_DOTS: Cờ này sẽ làm cho FileSystemIterator bỏ qua các thư mục ảo ("." Và "..").

  • FileSystemIterator :: UNIX_PATHS: Cờ này sẽ làm cho FileSystemIterator sử dụng thư mục unix Style Decelator () mặc dù hệ thống tập lệnh PHP chạy trên.

Nhìn trộm trước với bộ nhớ đệm

Trong phần này, chúng tôi sẽ giới thiệu một trình lặp với khả năng nhìn trộm vào phần tử tiếp theo trong một lần lặp. Tính năng này cho phép chúng tôi làm rất nhiều việc hữu ích như, thực hiện một cái gì đó khác biệt khi Iterator đạt đến cuối danh sách.

Lớp học với sức mạnh lớn này là bộ nhớ đệm.

Trước tiên chúng ta hãy xem nó chữ ký lớp, sau đó, chúng ta sẽ đi vào chi tiết về việc sử dụng nó.

class TrendingRepositoriesIterator implements Iterator
{
    public function rewind()
    {
    }
 
    public function valid()
    {
    }
 
    public function next()
    {
    }
 
    public function key()
    {
    }
 
    public function current()
    {
    }
}
4

Bộ nhớ đệm kế thừa từ IteratorIterator. Iteratoriterator là gì? Nó chỉ đơn giản là một trình bao bọc xung quanh một vòng lặp khác, dưới mui xe. Nó sẽ chuyển tiếp năm phương thức iterTator (tua lại (), dòng điện (), key (), hợp lệ (), tiếp theo ()) gọi đến trình lặp mà nó kết thúc xung quanh. Chúng ta cũng có thể truy xuất trình lặp bên trong bằng cách gọi phương thức getInnerIterator ().

Do tính chất của lớp này, con trỏ của bộ lặp bên trong luôn di chuyển trước một bước của bộ nhớ đệm và bộ nhớ đệm cung cấp một phương thức hasnext () để cho chúng tôi biết nếu nó đi đến cuối danh sách. Đó là cách bộ nhớ đệm nhìn trộm phía trước.

Bây giờ, chúng ta hãy đưa nó vào hành động.

class TrendingRepositoriesIterator implements Iterator
{
    public function rewind()
    {
    }
 
    public function valid()
    {
    }
 
    public function next()
    {
    }
 
    public function key()
    {
    }
 
    public function current()
    {
    }
}
5

Kết quả của việc chạy tập lệnh trên CLI:

class TrendingRepositoriesIterator implements Iterator
{
    public function rewind()
    {
    }
 
    public function valid()
    {
    }
 
    public function next()
    {
    }
 
    public function key()
    {
    }
 
    public function current()
    {
    }
}
6

Tương tự như các trình lặp khác, để tạo một thể hiện bộ nhớ đệm, chúng tôi chuyển trong trình lặp làm tham số đầu tiên cho nhà thầu lớp. Như chúng ta có thể thấy, phép thuật thực sự đằng sau việc nhìn trộm phía trước được cung cấp bởi phương thức hasnext (). Phương pháp này có thể cho chúng ta biết nếu có một yếu tố tiếp theo ngay lập tức.

Bên cạnh tham số đầu tiên, bộ nhớ đệm cũng tùy chọn chấp nhận tham số thứ hai làm cờ.

  • Bộ nhớ cacheiterator :: Call_ToString: Nó sẽ trả về Ostring của phần tử hiện tại là giá trị. Đây là hành vi mặc định.
  • Bộ nhớ cacheiterator :: Catch_get_child: Nó sẽ nắm bắt tất cả các trường hợp ngoại lệ khi truy cập trẻ em.
  • Bộ nhớ cacheiterator :: ToString_use_Key: Nó sẽ trả về giá trị khóa khi đúc trình lặp lại vào một chuỗi trong một vòng lặp.
class TrendingRepositoriesIterator implements Iterator
{
    public function rewind()
    {
    }
 
    public function valid()
    {
    }
 
    public function next()
    {
    }
 
    public function key()
    {
    }
 
    public function current()
    {
    }
}
7
  • Bộ nhớ cacheiterator :: toString_use_cien: Nó sẽ trả về giá trị hiện tại khi đúc iterator vào một chuỗi trong một vòng lặp.
class TrendingRepositoriesIterator implements Iterator
{
    public function rewind()
    {
    }
 
    public function valid()
    {
    }
 
    public function next()
    {
    }
 
    public function key()
    {
    }
 
    public function current()
    {
    }
}
8
  • Bộ nhớ cacheiterator :: ToString_use_inner: Nó sẽ trả về trình lặp bên trong được đúc thành một chuỗi khi đúc trình lặp vào một chuỗi trong một vòng lặp. Nếu chúng tôi đặt cờ này trong cùng một mã như ví dụ trước, nó sẽ ném một ngoại lệ. Điều này là do ArrayIterator không thực hiện phương thức toString ().
  • Bộ nhớ đệm :: full_cache: Bộ nhớ đệm sẽ không có từ khóa "bộ đệm" trong tên của nó nếu nó không thể thực hiện một số loại bộ đệm. Khi cờ này được đặt, nó sẽ lưu trữ kết quả, nếu chúng được lặp lại để sử dụng trong tương lai.

Máy phát điện

Bây giờ bạn bị thuyết phục bởi những lợi ích của người lặp. Họ gói gọn các chi tiết của việc đi qua và chúng hiệu quả hơn nhiều so với việc tạo ra các mảng trong bộ nhớ. Tuy nhiên, mọi thứ đều có giá của nó. Để tạo một iterator, chúng tôi vẫn phải triển khai giao diện LIT Iterator. Bạn có thể sợ hãi các trình lặp và không muốn thực hiện năm phương pháp được ký hợp đồng bởi giao diện Iterator. Đó là thời gian tốn thời gian và đôi khi thậm chí phức tạp để thực hiện chúng.

Bắt đầu từ Php 5.5, bạn sẽ không bị đe dọa nữa. PHP giới thiệu một cái gì đó, máy phát điện, cung cấp một cách dễ dàng để thực hiện các trình lặp đơn giản mà không có chi phí hoặc độ phức tạp của việc thực hiện một lớp thực hiện giao diện iterator.

Chính xác là một máy phát điện là gì? Một trình tạo giống như một hàm PHP bình thường, ngoại trừ việc nó có một từ khóa đặc biệt, "năng suất", trong đó.

Dưới đây là một ví dụ đơn giản về hàm máy phát. Chúng tôi sẽ không có một trình tạo như vậy trong ứng dụng trong thế giới thực - nó chỉ ở đây để trình diễn:

class TrendingRepositoriesIterator implements Iterator
{
    public function rewind()
    {
    }
 
    public function valid()
    {
    }
 
    public function next()
    {
    }
 
    public function key()
    {
    }
 
    public function current()
    {
    }
}
9

Trong nội bộ PHP nhận ra một hàm máy phát khi nó phát hiện từ khóa năng suất. Khi một hàm trình tạo được gọi lần đầu tiên, PHP sẽ tạo một đối tượng máy phát. Đối tượng Trình tạo này là một thể hiện của một trình tạo lớp nội bộ và lớp tạo thực hiện giao diện iterator. Bằng cách này, người dùng có thể tạo trình lặp mà không cần viết mã hợp đồng, tất cả là nhờ trình tạo PHP.

Năng suất được gọi khi chúng ta cần cung cấp các giá trị bước. Hãy nghĩ về nó như là Trả lại trong một hàm hoặc phương thức hiện tại trong một trình lặp thông thường.

Chúng ta hãy biến một trong những bộ phận lặp đầu tiên của chúng tôi TrendingRepositoryitorIterator thành hàm tạo:

?

class TrendingRepositoriesIterator implements Iterator
{
    private $repos = [];
    private $pointer = 0;
    public function __construct()
    {
        $this->populate();
    }
    public function rewind()
    {
        $this->pointer = 0;
    }
    public function valid()
    {
        return isset($this->repos[$this->pointer]);
    }
    public function next()
    {
        $this->pointer++;
    }
    public function key()
    {
        return $this->pointer;
    }
    public function current()
    {
        return $this->repos[$this->pointer];
    }
    private function populate()
    {
        $client = new GuzzleHttp\Client();
        $res = $client->request('GET', 'https://api.github.com/search/repositories', [ 'query' => ['q' => 'language:php', 'sort' => 'stars', 'order' => 'desc']]);
        $resInArray = json_decode($res->getBody(), true);
        $trendingRepos = array_slice($resInArray['items'], 0, 10);
        foreach ($trendingRepos as $rep) {
            $this->repos[] = $rep['name'];
        }
    }
}
0

Nó hóa ra là ít mã hơn với một trình tạo. Chúng ta cũng có thể sử dụng nó trong một vòng lặp foreach, giống như cách chúng ta đã làm với xu hướng repositoryitorator:

class TrendingRepositoriesIterator implements Iterator
{
    private $repos = [];
    private $pointer = 0;
    public function __construct()
    {
        $this->populate();
    }
    public function rewind()
    {
        $this->pointer = 0;
    }
    public function valid()
    {
        return isset($this->repos[$this->pointer]);
    }
    public function next()
    {
        $this->pointer++;
    }
    public function key()
    {
        return $this->pointer;
    }
    public function current()
    {
        return $this->repos[$this->pointer];
    }
    private function populate()
    {
        $client = new GuzzleHttp\Client();
        $res = $client->request('GET', 'https://api.github.com/search/repositories', [ 'query' => ['q' => 'language:php', 'sort' => 'stars', 'order' => 'desc']]);
        $resInArray = json_decode($res->getBody(), true);
        $trendingRepos = array_slice($resInArray['items'], 0, 10);
        foreach ($trendingRepos as $rep) {
            $this->repos[] = $rep['name'];
        }
    }
}
1

Lưu ý rằng bản thân các trình tạo không cung cấp bất cứ điều gì đặc biệt - họ chỉ làm cho việc tạo ra các trình lặp đơn giản hơn. Nói cách khác, chúng chắc chắn không phải là sự thay thế cho trình lặp.

Kết thúc

Hy vọng rằng hướng dẫn đơn giản này đã giúp bạn phát triển. Nếu bạn thích bài viết của chúng tôi, xin vui lòng theo dõi chúng tôi trên Twitter và giúp truyền bá. Chúng tôi cần sự hỗ trợ của bạn để tiếp tục. Chúng ta có bỏ lỡ điều gì không? Đừng để lại một bình luận dưới đây để cho chúng tôi biết.

Một người lặp là gì và tại sao iterator là cần thiết?

Trình lặp là một đối tượng (giống như một con trỏ) trỏ đến một phần tử bên trong thùng chứa. Chúng ta có thể sử dụng trình lặp để di chuyển qua nội dung của container. Chúng có thể được hình dung như một cái gì đó tương tự như một con trỏ trỏ đến một số vị trí và chúng ta có thể truy cập nội dung tại vị trí cụ thể đó bằng cách sử dụng chúng.an object (like a pointer) that points to an element inside the container. We can use iterators to move through the contents of the container. They can be visualized as something similar to a pointer pointing to some location and we can access the content at that particular location using them.

Chức năng nào sau đây là hàm tererator?

Iterator trong Java được sử dụng để đi qua từng yếu tố trong bộ sưu tập.Sử dụng nó, đi qua, thu được từng phần tử hoặc thậm chí bạn có thể loại bỏ.ListIterator mở rộng Itererator để cho phép giao dịch hai chiều của một danh sách và sửa đổi các yếu tố.traverse each and every element in the collection. Using it, traverse, obtain each element or you can even remove. ListIterator extends Iterator to allow bidirectional traversal of a list, and the modification of elements.

Người lặp trong PHP là gì?

Một iterator chứa một danh sách các mục và cung cấp các phương thức để lặp qua chúng.Nó giữ một con trỏ đến một trong các yếu tố trong danh sách.Mỗi mục trong danh sách nên có một khóa có thể được sử dụng để tìm mục.contains a list of items and provides methods to loop through them. It keeps a pointer to one of the elements in the list. Each item in the list should have a key which can be used to find the item.

Tại sao Iterator lại quan trọng?

Mục đích chính của trình lặp là cho phép người dùng xử lý mọi yếu tố của một thùng chứa trong khi cách ly người dùng với cấu trúc bên trong của container.Điều này cho phép container lưu trữ các yếu tố theo bất kỳ cách nào nó mong muốn trong khi cho phép người dùng xử lý nó như thể nó là một chuỗi hoặc danh sách đơn giản.to allow a user to process every element of a container while isolating the user from the internal structure of the container. This allows the container to store elements in any manner it wishes while allowing the user to treat it as if it were a simple sequence or list.