Определение итератора

Иногда в программировании стоит задача пройтись по публичным свойствами класса, чтобы либо их посчитать либо просто использовать в другой части программы. Например:

class A {
	public $e=1;
	public $c=2;
	public $f=3;
	}
	$f = new A;
	foreach ($f as $a => $b) {
		echo $a.'->'.$b.'<br>';
	}

Если мы добавим сюда защищенное свойство, то проитерировать (пройтись) защищенные свойства итератору уже не получится и просто так их напечатать на экран:

class A {
	public $e=1;
	public $c=2;
	public $f=3;
	protected $h=3;
	private $j =9;
}
	$f = new A;
	foreach ($f as $a => $b) {
		echo $a.'->'.$b.'<br>';
}

Как же нам вывести приватный или защищенное свойство объекта? Для этого нужно использовать специальной библиотекой языка PHP, которая называется SPL (https://www.php.net/manual/ru/book.spl.php) .Эта библиотека не требует установки и работает во всех версиях языка PHP выше 5.0. Данная библиотек включает в себя различные структуры данных и 24 итератора, позволяющих посчитать что-то в любом объекте. Другими словами, иттераторы позволяют организовать навигацию по любому объекту. Иерархия интерфейсов выглядит примерно таким образом:

1) интерфейс Traversable

 Traversable 
 	{
	
	}

Traversable является базовым интерфейсом. Именно он определяет является ли класс обходимым. Сам по себе его нельзя использовать, так как он абстрактный. Его можно реализовать черезз IteratorAggregate, Iterator.

2) интерфейс IteratorAggregate (https://www.php.net/manual/ru/class.iter...)

	IteratorAggregate extends Traversable 
		{
			// Методы  
			abstract public getIterator ( void ) : Traversable
		}

3) параллельно второму пункту ,мы можем использовать интерфейс iterator (https://www.php.net/manual/ru/class.iter...)

	Iterator extends Traversable 
		{
			// Методы  
			abstract public current ( void ) : mixed
			abstract public key ( void ) : scalar
			abstract public next ( void ) : void
			abstract public rewind ( void ) : void
			abstract public valid ( void ) : bool
		}

4) Из пунтка третьего, мы можем получить интерфейс OuterIterator

 OuterIterator extends Iterator {
// Методы 
public getInnerIterator ( void ) : Iterator
// Наследуемые методы 
abstract public Iterator::current ( void ) : mixed
abstract public Iterator::key ( void ) : scalar
abstract public Iterator::next ( void ) : void
abstract public Iterator::rewind ( void ) : void
abstract public Iterator::valid ( void ) : bool
}

5) Класс IteratorIterator. Из пункта 4 мы можем получить данный класс. (https://www.php.net/manual/ru/class.iter...

 IteratorIterator implements OuterIterator {
// Методы  
public __construct ( Traversable $iterator )
public current ( void ) : mixed
public getInnerIterator ( void ) : Traversable
public key ( void ) : mixed
public next ( void ) : void
public rewind ( void ) : void
public valid ( void ) : bool
}

6) Класс FilterIterator (https://www.php.net/manual/ru/class.filt...) получается из 5 пункта.

abstract FilterIterator extends IteratorIterator implements OuterIterator {
// Методы  
public abstract accept ( void ) : bool
public __construct ( Iterator $iterator )
public current ( void ) : mixed
public getInnerIterator ( void ) : Iterator
public key ( void ) : mixed
public next ( void ) : void
public rewind ( void ) : void
public valid ( void ) : bool
}

7) Класс DirectoryIterator (https://www.php.net/manual/ru/class.dire...)

8) ArrayItterator

class FileExtensionFilter extends FilterIterator
	{
	    // Белый список расширений файлов
	    protected $ext = ["phpq", "txtq"];
	    // Абстрактный метод, который надо реализовать в подклассе
	    public function accept() {
	        return in_array($this->getExtension(), $this->ext);
	    }
	}
	//Создаем новый итератор
	$dir = new FileExtensionFilter(new DirectoryIterator("./"));

Рассмотрим самые используемые типы иттераторов в данной библиотеке - итерратор ArrayItterator

$arr =['a','b','c'];
$itter = new ArrayIterator($arr);
foreach ($itter as $key =>$value) {
	echo $key.":".$value."<br>";
}
 

Обратите внимание, что мы просто создали объект уже встроенного класса "ArrayIterator", так как он уже встроен в язык PHP и определять его по новой не требуется
Познакомимся с классом DirectoryIterator для работы с файлами и директориям. В данном примере, мы выведем все файлы, которые находятся в директории "C:\OSPannel\OpenServer\domains\localhost":

	$dir = new DirectoryIterator ("C:\OSPannel\OpenServer\domains\localhost");
	foreach ($dir as $item)
	{
		echo $item."<br>";
	}

Как и у любого класса у DirectoryIterator есть свои методы, встроенные. Список всех методов можно посмотреть по ссылке: https://www.php.net/manual/ru/class.dire.... Всего их 29. Например, изучим метод

<?php
	class FSDirectory implements IteratorAggregate   
		{     
			public $path;     
			public function __construct($path)     
				{       
					$this->path = $path;     
				}        
			public function getIterator()     
				{       
					return new FSDirectoryIterator($this);     
				}   
		} 
	class FSDirectoryIterator implements Iterator   
		{     
			 private $owner;     
			 private $d = null;     
			 private $cur = false;       
			 public function __construct($owner)     
 				{       
					 $this->owner = $owner;       
					 $this->d = opendir($owner->path);       
					 $this->rewind();     
 				}     
 			public function rewind()     
 				{       
					 rewinddir($this->d);       
					 $this->cur = readdir($this->d);     
 				}     
 			public function valid()     
				 {       
				 	$this->cur !== false;     
				 }
			public function key()     
				{       
					return $this->cur;     
				}     
			public function current()     
				{      
					 $path = $this->owner->path."/".$this->cur;       
					 return is_dir($path)? new FSDirectory($path) : new FSFile($path);     
				 }       
 			public function next()     
				 {       
				 	$this->cur = readdir($this->d);     
				 }   
		} 


	class FSFile   
		{     
			public $path;        
			public function __construct($path)     
				{       
					$this->path = $path;     
				}     
			public function getSize()     
				{       
					return filesize($this->path);     
				}      
		}
	$d = new FSDirectory(".");   
	foreach ($d as $path => $entry) 
		{     
			if ($entry instanceof FSFile) 
				{      
					echo "<tt>$path</tt>: ".$entry->getSize()."<br>";     
				}   
		}