nulib/php/src_php/iter/AbstractIterator.php

150 lines
3.5 KiB
PHP

<?php
namespace nulib\php\iter;
use Exception;
use Iterator;
use nulib\NoMoreDataException;
use nulib\php\ICloseable;
/**
* Class AbstractIterator: implémentation de base d'un itérateur
*/
abstract class AbstractIterator implements Iterator, ICloseable {
/**
* initialiser les ressources nécessaires à l'itération.
*
* les exceptions lancées par cette méthode sont ignorées.
*/
protected function _setup(): void {}
/**
* lancer un traitement avant de commencer l'itération.
*
* cette méthode est appelée après {@link _setup()} et l'objet est garanti
* d'être dans un état valide.
*
* cette méthode est prévue pour être surchargée par l'utilisateur, mais il
* doit gérer lui-même les exceptions éventuelles.
*/
protected function beforeIter() {}
/**
* retourner le prochain élément.
* lancer l'exception {@link NoMoreDataException} pour indiquer que plus aucun
* élément n'est disponible
*
* le cas échéant, initialiser $key
*
* @throws NoMoreDataException
*/
abstract protected function _next(&$key);
/**
* modifier l'élement retourné par {@link _next()} avant de le retourner.
*
*
* cette méthode est prévue pour être surchargée par l'utilisateur, mais il
* doit gérer lui-même les exceptions éventuelles.
*/
protected function cook(&$item) {}
/**
* lancer un traitement avant de terminer l'itération et de libérer les
* resources
*
* cette méthode est appelée avant {@link _teardown()} et l'objet est garanti
* d'être dans un état valide.
*
* cette méthode est prévue pour être surchargée par l'utilisateur, mais il
* doit gérer lui-même les exceptions éventuelles.
*/
protected function beforeClose(): void {}
/**
* libérer les ressources allouées.
*
* les exceptions lancées par cette méthode sont ignorées.
*/
protected function _teardown(): void {}
function close(): void {
$this->rewind();
}
#############################################################################
# Implémentation par défaut
private $setup = false;
private $valid = false;
private $toredown = true;
private $index = 0;
protected $key;
protected $item = null;
function key() {
return $this->key;
}
function current() {
return $this->item;
}
function next(): void {
if ($this->toredown) return;
$this->valid = false;
try {
$item = $this->_next($key);
} catch (NoMoreDataException $e) {
$this->beforeClose();
try {
$this->_teardown();
} catch (Exception $e) {
}
$this->toredown = true;
return;
}
$this->cook($item);
$this->item = $item;
if ($key !== null) {
$this->key = $key;
} else {
$this->index++;
$this->key = $this->index;
}
$this->valid = true;
}
function rewind(): void {
if ($this->setup) {
if (!$this->toredown) {
$this->beforeClose();
try {
$this->_teardown();
} catch (Exception $e) {
}
}
$this->setup = false;
$this->valid = false;
$this->toredown = true;
$this->index = 0;
$this->key = null;
$this->item = null;
}
}
function valid(): bool {
if (!$this->setup) {
try {
$this->_setup();
} catch (Exception $e) {
}
$this->setup = true;
$this->toredown = false;
$this->beforeIter();
$this->next();
}
return $this->valid;
}
}