4. Iteracja po obiekcie
$object = new stdClass;
$object->key = 'value';
$object->key_2 = 'value_2';
foreach ($object as $key=>$value) {
echo $key.' => '.$value.PHP_EOL;
}
// key => value
// key_2 => value_2
5. Iteracja po obiekcie – tylko
właściwości publiczne
class foo {
public $key = 'value';
protected $key_2 = 'value_2';
private $key_3 = 'value_3';
static public $staticKey = 'value';
static protected $staticKey_2 = 'value_2';
static private $staticKey_3 = 'value_3';
}
$object = new foo;
foreach ($object as $key=>$value) {
echo $key.' => '.$value.PHP_EOL;
}
// key => value
6. Zachowanie iteracji wg obiektu
class MyIterator implements Iterator {
private $_tab = array();
public function __construct(array $tab){
$this->_tab = $tab;
}
public function current() { $object = new MyIterator(range(1,3));
return current($this->_tab).'_MyIteration'; foreach ($object as $key=>$value) {
} echo $key.' => '.$value.PHP_EOL;
public function next() { }
next($this->_tab); // rewind
} // check_valid
public function key() { // 0 => 1_MyIteration
return key($this->_tab); // check_valid
} // 1 => 2_MyIteration
public function valid() { // check_valid
echo 'check_valid' . PHP_EOL; // 2 => 3_MyIteration
return key($this->_tab) !== null; // check_valid
}
public function rewind() {
echo 'rewind' . PHP_EOL;
reset($this->_tab);
}
}
7. Iterator, IteratorAggregate oraz
Traversable
interface Iterator implements Traversable {
// definicja interfejsu
}
interface IteratorAggregate implements Traversable {
// definicja interfejsu
}
•
Grupuje dwa rodzaje iteratorów w jedno
•
Nie może być implementowany bez Iteratora lub IteratorAggregate
8. Traversable jako typowany
argument
function foo(Traversable $object) {
}
class Foo implements IteratorAggregate {
public function getIterator() {
return new EmptyIterator();
}
}
foo(new ArrayIterator()); // przykładowa implementacja Iterator
foo(new Foo()); // implementacja IteratorAggregate
9. Kiedy używać interfejsu Iterator?
●
Uzyskanie całkowitej kontroli nad zwracanymi
wartościami
●
Definiowanie własnych ścieżek poruszania po danych
●
Generowanie danych
10. Kiedy używać interfejsu Iterator?
class PaginationIterator implements Iterator {
// definicja prywatnych właściwości
public function __construct($entriesLength, $entriesPerPage = 20, $activePage = 1) {
$this->_entriesLength = (int)$entriesLength;
$this->_entriesPerPage = (int)$entriesPerPage;
$this->_activePage = (int)$activePage;
$this->_maxPages = (int)ceil($this->_entriesLength / $this->_entriesPerPage);
}
public function current() {
$object = new stdClass();
$key = $this->_iterationIndex;
$object->page = $key + 1;
$object->isActive = $key === ($this->_activePage - 1);
return $object;
}
public function next() { $this->_iterationIndex++; }
public function key() { return $this->_iterationIndex; }
public function valid() { return $this->_iterationIndex < $this->_maxPages; }
public function rewind() { $this->_iterationIndex = 0; }
}
12. Kiedy używać interfejsu
IteratorAggregate?
●
Szybkie zwrócenie danych do iteracji
●
Idealne we wszelkiego rodzaju klasach
agregujących listy wartości
●
Brak konieczności obróbki danych
13. Kiedy używać interfejsu
IteratorAggregate?
class Form implements IteratorAggregate {
private $_elements = array();
public function addElement(FormElement $element) {
$this->_elements[] = $element;
}
public function getIterator() {
return new ArrayIterator($this->_elements);
}
}
class FormElement {
public function __construct($type, $name) {
$this->type = $type;
$this->name = $name;
}
}
14. Kiedy używać interfejsu
IteratorAggregate?
$form = new Form();
$form->addElement(new FormElement('text', 'name'));
$form->addElement(new FormElement('test', 'surname'));
foreach ($form as $element) {
echo 'Type: '.$element->type;
echo ' Name: '.$element->name.PHP_EOL;
}
// Type: text Name: name
// Type: test Name: surname
17. SPL – Dodatkowe interfejsy
iteratorów
RecursiveIterator
$array = array( 1, 2,
array(3, 4, 5)
);
$iterator = new RecursiveArrayIterator($array);
foreach ($iterator as $key=>$value) {
if ($iterator->hasChildren()) {
echo 'children'.PHP_EOL;
foreach ($iterator->getChildren() as $key => $value) {
echo $key.' => '.$value.PHP_EOL;
}
} else {
echo 'no children'.PHP_EOL;
}
}
// no children
// no children
// children
// 0 => 3
// 1 => 4
// 2 => 5
18. SPL – ArrayIterator
● Wszystkie możliwości sortowania (natsort,
usort, ksort)
● Dostęp do wartości za pomocą []
● Zliczanie ilości elementów
● Dodawanie kolejnych elementów
● Serializacja, deserializacja
19. SPL – RecursiveIteratorIterator
● Iteruje rekursywnie po RecursiveIterator
● Niezwykle potężne narzędzie do obsługi
struktur drzewiastych oraz wszelkich
zagnieżdżeń
● 3 tryby iteracji
● LEAVES_ONLY
● SELF_FIRST
● CHILD_FIRST
22. SPL – CallbackFilterIterator –
od PHP 5.4
class CallbackFilterIterator extends FilterIterator {
private $_callback;
public function __construct(Iterator $iterator, Closure $callback) {
parent::__construct($iterator);
$this->_callback = $callback;
}
public function accept() {
return call_user_func(
$this->_callback,
$this->current(),
$this->key(),
$this->getInnerIterator());
}
}
23. SPL – CallbackFilterIterator
class Form implements IteratorAggregate {
public function getElementsByType($type) {
return new CallbackFilterIterator(
$this->getIterator(),
function($element) use ($type) {
return $type === $element->type;
});
}
}
$form = new Form();
$form->addElement(new FormElement('text', 'name'));
$form->addElement(new FormElement('number', 'age'));
$form->addElement(new FormELement('range', 'weight'));
foreach ($form->getElementsByType('text') as $element) {
echo 'Type: '.$element->type;
echo ' Name: '.$element->name.PHP_EOL;
}
// Type: text Name: name
24. SPL - AppendIterator
$form = new Form();
$form->addElement(new FormElement('text', 'name'));
$form->addElement(new FormElement('number', 'age'));
$form->addElement(new FormELement('range', 'weight'));
$iterator = new AppendIterator();
$iterator->append($form->getElementsByType('text'));
$iterator->append($form->getElementsByType('range'));
foreach ($iterator as $element) {
echo 'Type: '.$element->type;
echo ' Name: '.$element->name.PHP_EOL;
}
// Type: text Name: name
// Type: range Name: weight
25. SPL - DirectoryIterator
● Rozszerza SplFileInfo – cała masa
dobrodziejstw
$iterator = new DirectoryIterator('some_dir');
foreach ($iterator as $file) {
echo $file->getPathName().PHP_EOL;
}
// some_dir.
// some_dir..
// some_dirtest_file.txt
// some_dirtest_file_2.txt
26. SPL - RegexIterator
$array = array(
'Jabłko', 'Banan', 'Ananas', 'Wiśnia', 'Arbuz'
);
$iterator = new ArrayIterator($array);
$iterator = new RegexIterator($iterator, '/nas?/i');
foreach ($iterator as $string) {
echo $string.PHP_EOL;
}
// Banan
// Ananas
● Jest w stanie wykonywać replace, split
27. Wespół w zespół –
przeszukiwanie katalogów
$iterator = new RecursiveDirectoryIterator('PHPUnit/Extensions');
$iterator = new RecursiveIteratorIterator($iterator);
$iterator = new RegexIterator($iterator, '/_coverage/i');
foreach ($iterator as $file) {
echo $file->getPathName();
}
// PHPUnit/Extensions/SeleniumTestCase/phpunit_coverage.php
28. SPL – InfiniteIterator – Tasks
class TaskDownloader extends ArrayIterator {
public function __construct() {
// lock constructor
}
public function rewind() {
$iteration = 0;
do {
$tasks = $this->fetch();
if ($iteration > 0) {
usleep(1000);
}
$iteration++;
} while ($tasks === array());
parent::__construct($tasks);
}
public function fetch() {
// fetch tasks from tasks repository
}
}
$iterator = new InfiniteIterator(new TaskDownloader());
foreach ($iterator as $task) {
echo $task;
}
29. Iteratory oszczędzają pamięć
●
Nie potrzebują wszystkich danych od
samego początku
●
Są w stanie generować, pobierać dane
30. Pobieranie dużej ilości rekordów
class PDODataPartition extends Iterator {
public function rewind() {
$this->_loadPartition(0);
$this->_position = 0;
}
public function valid() {
if (isset($this->_data[$this->_position])) { return true; }
if ($this->_position < $this->_partitionSize) { return false; }
if ($this->_loadPartition(++$this->_partitionNum)) {
$this->_position = 0;
return true;
}
return false;
}
protected function _loadPartition($numOfPartition) {
$this->_partitionNum = (int)$numOfPartition;
$query = $this->_getPartitionQuery();
$stmt = $this->_pdo->query($query);
if ($stmt) { $this->_data = $stmt->fetchAll(); }
return (bool)$this->_data;
}
protected function _getPartitionQuery() {
$offset = $this->_partitionNum * $this->_partitionSize;
$limit = $this->_partitionSize;
return $this->_query.' LIMIT '.$limit.' OFFSET '.$offset;
}
}
31. Pobieranie dużej ilości rekordów
$records = $pdo->query('SELECT * FROM tabela')->fetchAll();
foreach ($records as $record) {}
// vs
$iterator = new PDODataPartition($pdo, 'SELECT * FROM tabela', 1000);
foreach ($iterator as $record) {}
PDO PDODataPartition
Pamięć 562 552 25 896
Czas 0,231 s 0,930 s
Więcej: http://bit.ly/uGQ0Vl
32. Iterator w php 5.4 - Trait
trait IteratorTrait {
protected $_data = array();
public function next() { next($this->_data); }
public function current() { return current($this->_data); }
public function valid() { return key($this->_data) !== null; }
public function key() { return key($this->_data); }
public function rewind() { reset($this->_data); }
}
class SomeOtherClass { }
class TestIterator extends SomeOtherClass implements Iterator {
use IteratorTrait;
public function __construct(array $data) { $this->_data = &$data; }
}
$o = new TestIterator(range(1, 5));
foreach ($o as $key => $value) {
echo $key.' => '.$value.PHP_EOL;
}