2012-11-29 34 views
9

Các IteratorAggregate là một giao diện để tạo ra một Iterator bên ngoài:Giao diện PHP IteratorAggregate vs Iterator?

class myData implements IteratorAggregate 
{ 
    public $property1 = "Public property one"; 
    public $property2 = "Public property two"; 
    public $property3 = "Public property three"; 

    public function __construct() 
    { 
     $this->property4 = "last property"; 
    } 

    public function getIterator() 
    { 
     return new ArrayIterator($this); 
    } 
} 

$obj = new myData; 

Và bạn sẽ có thể đi qua các đối tượng sử dụng foreach:

foreach($obj as $key => $value) { 
    var_dump($key, $value); 
    echo "\n"; 
} 

Trong khi Iterator là một giao diện cho các trình lặp hoặc đối tượng bên ngoài có thể tự lặp lại trong nội bộ:

class myIterator implements Iterator 
{ 
    private $position = 0; 
    private $array = array('one', 'two', 'three'); 

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

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

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

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

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

Và một lần nữa, bạn có thể đi qua nó về cơ bản theo cùng một cách:

$it = new myIterator; 

foreach($it as $key => $value) { 
    var_dump($key, $value); 
    echo "\n"; 
} 

Vì vậy, bất cứ ai có thể giải thích lý do tại sao chúng ta cần hai giao diện và sự khác biệt giữa chúng là gì?

Trả lời

12

Tôi giả định IteratorAggregate là dành cho các trường hợp bạn muốn tiết kiệm thời gian và Iterator dành cho các trường hợp bạn cần kiểm soát tốt việc lặp qua đối tượng của mình. Ví dụ: nó cho phép bạn thêm ngoại lệ tùy chỉnh vào next(), key() hoặc prev() lỗi, lưu vào bộ nhớ cache (nếu bạn lặp qua thứ gì đó lấy dữ liệu qua mạng), các giá trị tiền xử lý trước khi trả lại chúng.

+0

Tôi nghĩ bạn sai về các phương pháp tùy chỉnh. – tacone

+0

Và nếu bạn muốn tiết kiệm nhiều thời gian hơn, bạn có thể chỉ cần 'yield' các giá trị từ' getIterator'. – Bell

6

IteratorAggregate là cách dễ dàng để triển khai Iterator. Điểm bất lợi là bạn không thể thêm next(), key(), vv các phương thức, vì chúng sẽ không được gọi trong quá trình truyền tải thông thường foreach.

Nếu bạn cần triển khai các phương thức tùy chỉnh, bạn cần triển khai OuterIterator hoặc (dễ dàng hơn) để mở rộng IteratorIterator.

Lợi thế với IteratorAggregate là tốc độ, tốc độ này nhanh hơn nhiều so với các lựa chọn thay thế của nó. Vấn đề với nó là ... mặc dù tên nó không phải là một iterator nhưng một traversable (như vậy một lần nữa, không có tiếp theo, chính, hiện tại, hợp lệ, phương pháp tua lại).

Dưới đây là một chuẩn mực đơn giản, tôi chạy trên máy tính xách tay nghèo của tôi với 1 triệu lần lặp lại cho mỗi người IteratorAggregate, IteratorIteratorOuterIterator cả sử dụng iterator_to_arrayforeach: (cũng lưu ý các echo bên trong phương pháp next tổng hợp của: không có 'x' được in, giấy tờ chứng minh nó không bao giờ gọi)

$ repeat 3 php benchIterator.php 
------------------------------------ 
Outer_ToArray: 569.61703300476 ms 
Aggregate_ToArray: 552.38103866577 ms 
IteratorIt_ToArray: 546.95200920105 ms 
Outer_Foreach: 1679.8989772797 ms 
IteratorIt_Foreach: 1019.6850299835 ms 
Aggregate_Foreach: 367.35391616821 ms 
------------------------------------ 
Outer_ToArray: 570.75309753418 ms 
Aggregate_ToArray: 544.40784454346 ms 
IteratorIt_ToArray: 555.06300926208 ms 
Outer_Foreach: 1682.2130680084 ms 
IteratorIt_Foreach: 988.21592330933 ms 
Aggregate_Foreach: 356.41598701477 ms 
------------------------------------ 
Outer_ToArray: 566.06101989746 ms 
Aggregate_ToArray: 543.1981086731 ms 
IteratorIt_ToArray: 546.28610610962 ms 
Outer_Foreach: 1663.2289886475 ms 
IteratorIt_Foreach: 995.28503417969 ms 
Aggregate_Foreach: 356.16087913513 ms 

Dưới đây là đoạn code tôi sử dụng cho điểm chuẩn:

<?php 

class Aggregate implements \IteratorAggregate 
{ 
    protected $var; 

    public function __construct($var = null) 
    { 
     if (is_array($var)) { 
      $this->var = new ArrayIterator($var); 
     } 
     if ($var instanceof \Traversable) { 
      $this->var = $var; 
     } 
    } 
    public function next() 
    { 
     echo 'x'; 
    } 
    public function toArray() 
    { 
     return iterator_to_array($this->var, true); 
    } 

    public function getIterator() 
    { 
     return $this->var; 
    } 

} 

class Outer implements \OuterIterator 
{ 
    protected $var; 

    public function __construct($var = null) 
    { 
     if (is_array($var)) { 
      $this->var = new ArrayIterator($var); 
     } 
     if ($var instanceof \Traversable) { 
      $this->var = $var; 
     } 
    } 

    public function toArray() 
    { 
     return iterator_to_array($this->var, true); 
    } 

    public function getInnerIterator() 
    { 
     return $this->var; 
    } 

    public function current() 
    { 
     return $this->var->current(); 
    } 
    public function next() 
    { 
     $this->var->next(); 
    } 
    public function key() 
    { 
     return $this->var->key(); 
    } 
    public function valid() 
    { 
     return $this->var->valid(); 

    } 
    public function rewind() 
    { 
    $this->var->rewind(); 

    } 
} 


class IteratorIt extends IteratorIterator 
{ 
    public function __construct($var = null) 
    { 
     if (is_array($var)) { 
      $var = new ArrayIterator($var); 

     } 
     parent::__construct($var); 

    } 

    public function toArray() 
    { 
     return iterator_to_array($this->getInnerIterator(), true); 
    } 
    public function getIterator() 
    { 
     return $this->getInnerIterator(); 
    } 
} 

function bench($name, $test) 
{ 
    echo "$name: "; 
    $start = microtime(true); 
    $test(); 
    $time = microtime(true); 
    $time -= $start; 

    echo ($time * 1000) . ' ms' . PHP_EOL; 
} 

$max = 1e6; 
$array = range (1, 1e6); 
$testSuites = [ 
    'Outer_ToArray' => function() use ($max, $array) { 
     $iterator = new Outer($array); 
     $r = $iterator->toArray(); 
    }, 
    'Aggregate_ToArray' => function() use ($max, $array) { 
     $iterator = new Aggregate($array); 
     $r = $iterator->toArray(); 
    }, 
    'IteratorIt_ToArray' => function() use ($max, $array) { 
     $iterator = new IteratorIt($array); 
     $r = $iterator->toArray(); 
    }, 
    'Outer_Foreach' => function() use ($max, $array) { 
     $iterator = new Outer($array); 
     foreach ($iterator as $k => $v) 
     { 

     } 
    }, 
    'IteratorIt_Foreach' => function() use ($max, $array) { 
     $iterator = new IteratorIt($array); 
     foreach ($iterator as $k => $v) 
     { 

     } 
    }, 
    'Aggregate_Foreach' => function() use ($max, $array) { 
     $iterator = new Aggregate($array); 
     foreach ($iterator as $k => $v) 
     { 

     } 
    }, 
]; 

echo '------------------------------------'.PHP_EOL; 
foreach ($testSuites as $name => $test) { 
    bench($name, $test); 
} 
3

Sự khác nhau giữa chúng là gì?

Sự khác biệt về tên ("Tổng hợp").

Ý nghĩa của tổng hợp là gì?

Trạng thái tổng hợp đảm bảo tính nhất quán của các thay đổi được thực hiện trong tổng hợp bằng cách cấm các đối tượng bên ngoài giữ tham chiếu đến các thành viên của nó. (wikipedia)


Mã TC:

class myData implements IteratorAggregate {//your implementation} 

class myIterator implements Iterator {//your implementation} 

Dưới đây là đoạn code cho rõ ràng của tổng hợp:

$renderFunction = function($iterator) { 
    foreach($iterator as $key => $value) { 
     echo "$key: $value\n"; 
     foreach($iterator as $key => $value) { 
      echo " $key: $value\n"; 
     } 
    } 
}; 

$renderFunction(new myData); // Aggregate on 
$renderFunction(new myIterator); // Aggregate off 

gì bạn mong đợi trong trường hợp này?

https://3v4l.org/JHDNQ

property1: Public property one 
    property1: Public property one 
    property2: Public property two 
    property3: Public property three 
    property4: last property 
property2: Public property two 
    property1: Public property one 
    property2: Public property two 
    property3: Public property three 
    property4: last property 
property3: Public property three 
    property1: Public property one 
    property2: Public property two 
    property3: Public property three 
    property4: last property 
property4: last property 
    property1: Public property one 
    property2: Public property two 
    property3: Public property three 
    property4: last property 

vs

0: one 
    0: one 
    1: two 
    2: three 
+0

Tôi tò mò, trong liên kết bạn cung cấp, có vẻ như php7 chậm hơn so với php 5.6 chẳng hạn. Điều này có bình thường không? hoặc tôi không hiểu dữ liệu ở tất cả – Dazag

+0

@ Dazag Bạn nói đúng, nhưng nó hơi khác biệt theo thời gian và tôi không biết là có opcache được sử dụng .... –

2

Bằng cách thực hiện IteratorAggregate, chúng tôi ủy thác công việc thực hiện chức năng iterator (key(), next(), current(), valid(), rewind()) đến lớp khác (bằng cách chỉ thực hiện getIterator().

Bằng cách này, nó giúp chúng ta đạt được các mối quan tâm riêng biệt trong OOP.

Các vấn đề liên quan