Not always
The iterator implies overhead if the collection is very small
And, use iterators is not a rule, they can add unnecessary complexity
How many times did you see methods like prepareXXX() ?
private function prepareArrayToInsertInBd(array $rows) {
$prepared_rows = array();
foreach($rows as $row) {
$prepared_row = array();
$prepared_row['id_row'] = $row['id'];
$prepared_row['title'] = trim($row['post_title']);
/* more stuff */
$prepared_rows[] = $prepared_row;
}
return $prepared_rows;
}public function getPostsData() {
/* ... some stuff */
$authors_cached_data = array();
foreach ($posts_data as &$post) {
$author_id = $post['author_id']
// Avoid request already requested author data.
if (!isset($authors_cached_data[$author_id])) {
$authors_cached_data[$author_id] = ApiCaller::getData( ... );
}
$post['author_data'] = $authors_cached_data[$author_id];
}
return $posts_data;
}
We just made unnecessary api calls...
We can have performance problems if we create a large collection of objects...
Typical RowsetIterator creates the entity object only when is requested.
$array = array(
array('pear', 'apple'),
array('banana', 'coconut'),
'orange' // This is not an array element
);
foreach ($array as $value) {
// Check type of element...
if (is_array($value)) {
foreach ($value as $fruit) {
echo $fruit . PHP_EOL;
}
} else {
echo $value . PHP_EOL;
}
}
/* OUTPUT:
pear
apple
banana
coconut
orange
*/$iterator = new RecursiveArrayIterator($array);
foreach(new RecursiveIteratorIterator($iterator) as $value) {
echo $value . PHP_EOL;
}RecursiveIteratorIterator is a decorator that does the check if the element is an array for us.
$object = new stdClass();
$object->property1 = 'property 1';
$object->property2 = 'property 2';
$array = array(
array('pear', 'apple'),
array('banana', 'coconut'),
'orange', // This is not an array element
$object
);
$iterator = new RecursiveArrayIterator($array);
foreach(new RecursiveIteratorIterator($iterator) as $value) {
echo $value . PHP_EOL;
}
/* OUTPUT: http://3v4l.org/RNKd1
pear
apple
banana
coconut
orange
property 1
property 2
*/PHP can iterate the public properties of the objects by default
/**
*
* @include_author_data boolean If true, the posts data will
* include the author data.
* @return array
*/
public function getPostsData($include_author_data = true) {
/* ... some stuff */
if ($include_author_data) {
foreach ($posts_data as &$post) {
$author_id = $post['author_id']
$post['author_data'] = ApiCaller::getData( ... );
}
}
return $posts_data;
}
$object->getPostsData(false);
//WTF is false? you have to enter to the method to know...We can do:
PostsDataIterator implements IteratorAggregate {
protected $collection;
public function __construct() {
$collection = $this->getPostsData();
}
protected function getPostsData() {
/* query code ... etc */
return $posts;
}
public function getInnerIterator() {
return new ArrayIterator($this->collection);
}
}
PostsDataWithAuthor extends PostsDataIterator {
protected function getPostsData() {
foreach (parent::getPostsData() as &$post) {
/* get author data... */
}
return $posts;
}
}When you pass an array between methods, PHP will make a copy.
If you pass objects, PHP will pass refererences.
With large arrays, this may be a problem if the array is passed for many methods.
$fruits = new ArrayIterator(array(
'apple',
'banana',
'cherry',
'orange',
'pear'
));
// Request the elements from a non existing position
foreach (new LimitIterator($fruits, 10, 5) as $fruit) {
var_dump($fruit);
}
/* OUTPUT:
Fatal error: Uncaught exception 'OutOfBoundsException'
with message 'Seek position 10 is out of range' in /in/lDOgh:13
*/Provides a simply interface to implements complex filter rules
abstract FilterIterator extends IteratorIterator implements OuterIterator {
/* Métodos */
public abstract bool accept ( void )
public __construct ( Iterator $iterator )
public mixed current ( void )
public Iterator getInnerIterator ( void )
public mixed key ( void )
public void next ( void )
public void rewind ( void )
public bool valid ( void )
}<?php
// avoid the use of the PHP native functions in procedural style.
foreach (new DirectoryIterator('/secret_folder/porn') as $fileInfo) {
if($fileInfo->isDot()) continue;
echo $fileInfo->getFilename() . "<br>\n";
}
// similar to glob PHP function
foreach (new \GlobIterator("*.php") as $php_file) {
echo "$php_file\n";
}
<?php
$iterator1 = new ArrayIterator(array(1,2));
$iterator2 = new ArrayIterator(array(3,4));
$appendIterator = new AppendIterator();
$appendIterator->append($iterator1);
$appendIterator->append($iterator2);
foreach($appendIterator as $element) {
echo $element . PHP_EOL;
}
/*OUTPUT
1
2
3
4
*/<?php
$fruits = new ArrayIterator(array(
'apple',
'banana',
'cherry',
'orange',
'pear'
));
// Passing by the custom iterator only a substet of the elements
foreach (new MyCustomIterator(new LimitIterator($fruits , 2, 2)) as $fruit) {
var_dump($fruit);
}(END)