Рейтинг
0.00
голосов:
0
avatar

Сайт на PHP  

SPL Iterators

Базовые понятия
Итераторы (Iterators) — это классы которые реализуют интерфейс Iterator. Реализация данного интерфейса необходима при организации доступа к циклическим структурам (массивы, списки и т.д.).

В SPL (Standard PHP Library) существует большое количество готовых классов, реализующих интерфейс Iterator.

Далее перечислены классы, которые непосредственно реализуют интерфейс Iterator: Traversable, IteratorAgregate, OuterIterator, RecursiveIterator. Остальные классы-итераторы SPL наследуют свои интерфейсы уже от них.

Не смотря на все обилие существующих классов иногда их оказывается недостаточно для решения поставленной задачи, тогда программист может создать свои собственные классы реализующие интерфейс Iterator.

Так как интерфейс Iterator входит в библиотеку стандартных классов PHP (Standard PHP Library), то его реализация выполнена в исходниках самого интерпретатора (имеются в виду коды программы на языке «С»). Если выразить этот интерфейс на языке PHP, то он будет выглядеть так:

interface Iterator{
  public function current(); // возвращает значение текущего элемента
  public function key(); // возвращает значения текущего ключа элемента (индекс массива например)
  public function next(); // смещает указатель на следующий элемент
  public function rewind(); // смещает указатель на первый элемент
  public function valid(); // определяет наличие элемента (выполняется после next или rewind)
}


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

Вспомогательные функции при работе с итераторами.

iterator_to_array(Iterator $iteratorObject) — возвращает содержимое объекта-итератора в виде массива.

iterator_count(Iterator $iteratorObject)) — возвращает количество элементов в объекте-итераторе.

Пример использования:


$a = Array('a', 'b', 'c');
$iterator = new ArrayIterator($a);
echo iterator_count($iterator); // Результат - 3


iterator_apply(Iterator iteratorObject, function callback, [user_data) — данная функция позволяет с помощью callback-а обработать каждый элемент содержащийся в объекте-итераторе.

Пример использования:

function print_entry($iteratorObject) {
   var_dump($iterator->current());
   return true;
}

$a = Array('a', 'b', 'c');
$iterator = new ArrayIterator($a);
iterator_apply($iterator, 'print_entry', array($iterator));


Если функция callback возвращает значение отличное от true перебор элементов объекта-итератора прекращается.

Поиск и сортировка файлов средствами PHP (SPL)

В старых версиях PHP для работы с файлами и каталогами предусмотрены такие функции как open_dir, read_dir и т.д. Начиная с 5-ой версии PHP для работы с файловой структурой намного удобнее использовать классы SPL (Standard PHP Library). Для наглядности предлагаю разобрать небольшой пример.

Допустим, нам необходимо просканировать дерево каталогов и найти в них все файлы. Затем полученный список нужно отсортировать в алфавитном порядке. Вот как эту задачу можно решить используя SPL:


$dirTree = new RecursiveDirectoryIterator("./testDir");
$sortedFileList = new FileSorterIterator(new RecursiveItertatorIterator($dirTree));

foreach($sortedFileList as $file) {
    echo $file->getFilename() . '<br />';
}


class FileSorterIterator extends SplHeap
{
        
    public function __constructor(Iterator $iterator) {
         foreach ($iterator as $item) {
        	if ($item->isFile()) { 
                  // отсеиваем директории, 
                  // так как в условиях нашей задачи нужно получить только список файлов
              	  $this->insert($item);
        	}
        }

    }

    public function compare($b,$a)
    {
        return strcmp($a->getFilename(), $b->getFilename());
    }
    
}


Как видите, пример получился очень простым. Если в старых версиях PHP приходилось самостоятельно отслеживать указатель на открытую директорию и своевременно его закрывать, то теперь всю «грязную» работу берут на себя классы SPL.

Теперь давайте разберемся какие классы SPL используются в примере:

Класс RecursiveDirectoryIterator
RecursiveDirectoryIterator — это класс SPL который рекурсивно просматривает заданную директорию и составляет дерево всех файлов и директорий. При создании класса нужно указать директорию в которой должен осуществляться поиск.

Для того, чтобы работать с построенным деревом используются стандартные функции интерфейса Iterator, а так же несколько специфичных для данного класса методов.

При работе с данным классом нужно помнить, что функции на подобие foreach перебирают только элементы файловой структуры, находящиеся в корне построенного дерева. Для того, чтобы перебрать элементы расположенные ниже по структуре (имеются в виду вложенные директории) следует использовать специальный класс RecursiveIteratorIterator.

Класс RecursiveIteratorIterator
RecuriveIteratorIterator — это класс созданный для последовательно перебора элементов древовидных итераторов. В нашем примере данный класс используется для того, чтобы обработать файлы расположенные в поддиректориях корневой директории.

Класс FileSorterIterator
FileSorterIterator — это пользовательский класс созданный на базе класса SplHeap. Данный класс нужен для того, чтобы отсортировать файлы в алфавитном порядке. Для этого, используется функция compare, которая содержит условие сортировки, исходя из которого и определяется место элемента в общем массиве.

Исключительные ситуации
Теперь, хочется пару слов сказать о том, что делать если в результате работы указанных классов возникает какая-то ошибка. Например, мы указали для сканирования несуществующую директорию:


$dirTree = new RecursiveDirectoryIterator("./noneExistDirectory");


При возникновении ошибки в работе SPL классов генерируется соответствующее исключение, в случае если эти исключения не обрабатываются, они приводят к останову работы программы в целом. Поэтому лучше предусмотреть обработку наиболее вероятных исключительных ситуаций в программе.

Исключительные ситуации обрабатываются следующим образом:


try{
     $dirTree = new RecursiveDirectoryIterator("./testDasdfsdf");
}catch(Exception $e) {
     var_dump($e->getMessage());
}


В примере вся обработка сводится к выводу сообщения о полученном исключении на экран — RecursiveDirectoryIterator::__construct(./testDasdfsdf): failed to open dir: No such file or directory. В реальном приложении такая обработка, естественно, не подходит, поэтому вместо вывода сообщений на экран стоит придумать, что-то посерьезнее.

Что такое PHP SPL

SPL — это набор стандартных библиотек PHP (Standard PHP Library) появившихся начиная с 5-ой версии PHP.
Если рассматривать SPL с позиции разработчика, то легко выделить шесть основных классов и интерфейсов, функционал которых расширяется в большом множестве классов-потомков.

Класс ArrayAccess
ArrayAccess — это интерфейс который позволяет создать классы которые будут вести себя как массивы. В других языках эта возможность наиболее часто предоставляется с помощью интерфейсов-счетчиков (indexer).

Класс Exception;
Exception — это родительский класс SPL для большого количества классов-потомков (LogicExeption, DomainEception, RangeException и т.д.), которые «выбрасываются» при наступлении той или иной исключительной ситуации.

Класс Iterator
Iterator — это интерфейс SPL который предназначен для реализации объектов с циклической структурой. Реализация данного интерфейса в разрабатываемых классах позволяет стандартным функциям PHP (например foreach) работать с пользовательскими объектами.

Класс IteratorAgregate
IteratorAgregate — это интерфейс SPL который содержит только один метод — «getIterator». Этот интерфейс позволяет не реализовывать в классе интерфейс «Itertator», а использовать вместо этого внешний итератор.

Класс Serializable
Serializable — это интерфейс который позволяет сериализовать любой объект с помощью функций Serialize и Unserrialize

Класс Traversable
Traversable — это служебный класс SPL который используется в интерфейсах Iterator и IteratorAgregate. Реализовать данный интерфейс в PHP-программе нельзя т.к. он реализован на урове C-кода интерпретатора PHP.

Кроме этого есть несколько других возможностей таких как шаблон проектирования «observer», вспомогательные функции для идентификации объекта и для работы с итераторами. Так же есть функционал позволяющий автоматизировать процесс загрузки классов и интерфейсов.

Передача переменных в PHP Array

Хотелось бы поделиться информацией о том, как можно передавать переменные в конструктор конструкции array(). Не могу сказать, что информация полезная, но может быть кому-то она покажется забавной.

На практике очень часто возникает задача инициализировать массив с помощью заранее созданных переменных. Для этого как правило используется следующая конструкция:


$someVar = 'Значение 1';

$arr = array(
     $someVar
);


Но кроме этого метода существует еще один, вполне законный метод сделать тоже самое:


$someVar = 'Значение 2';
$arr = array( 
       "$someVar"
);


Кто не понял, во втором случае используются двойные кавычки.

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

Работа с массивами в PHP

Один из самых используемых инструментов в языке PHP — это массивы. Поэтому, важно не только знать что такое массив, но и уметь правильно пользоваться тем разнообразием функций, которые предлагает PHP при обработке массивов.

Прежде чем перейти к основной теме статьи хочется дать один простой, но очень важный совет всем начинающим веб-программистам. (Этот совет настолько важен, что я даже позволил себе нарушить порядок изложения материала).

Если Вы программируете на PHP и у Вас появилась необходимость обработать данные сохраненные в массиве. Прежде чем писать собственную функцию обработки, проверьте что Ваша задача точно не может быть решена стандартными функциями PHP.


Помните, для действительно важных и часто встречающихся задач при обработке массивов существуют готовые функции и конструкции языка, которые созданы с единственной целью — максимально ускорить работу скриптов.

Вероятность того, что Ваша задача уникальна и требует особого решения крайне мала. Даже если задача не решается с помощью одной функции, постарайтесь разбить ее на несколько более простых частей и использовать готовые функции PHP.

Теперь, после того, как мы уяснили важность использования стандартных функций PHP для обработки массивов давайте вернемся к теме статьи.

Что такое массив?

Так как эта статья рассчитана на новичков, то и начать стоит с определения того, чем же все-таки является массив. Вот мое вольное определение массива:

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


Как в PHP создать массив

В PHP массив создается с помощью служебного слова array(). Существуют два варианта создания массива — это создание «пустого» массив и массива с предопределенными величинами:


$emptyArr = array(); // «пустой» массив
$someArr = array( 1, 2, 'Москва' ); // массив состоящий из элементов чисел «1», «2» и слова «Москва»;


В данном пример хотелось бы обратить внимание, на несколько вещей:

Во-первых, переменные, содержащиеся в массиве, могут быть разных типов. Так в массиве $someArr содержатся две целочисленные переменные и одна строковая.

Во-вторых, в приведенном определении массива, говорилось о том, что каждый элемент должен иметь уникальный индекс, а в примере этих индексов не видно.

Все дело в том, что в случае если при создании массива индексы не указаны явно, они будут созданы автоматически. Каждому элементу будет сопоставлен индекс вычисленный по следующей формуле:

«индекс» = «порядковый номер элемента» — 1


Конечно, если нас не устраивает, то каким образом PHP расставляет индексы массивов, мы можем определить их самостоятельно:

$someArr = array( 100 => 1, 200 => 2, 'city' => 'Москва' );


В данном примере числу «1» сопоставлен индекс «100», числу «2» индекс «200», а слову «Москва» сопоставлен строковый индекс «city».

Таким образом, мы приходим к третьему выводу о том, что в PHP индексами массива могут быть не только целые числа, но и строковые значения.

Как получить элемент массива в PHP?

Удобство массива заключается в том, что с ним можно работать как с обычной переменной — т.е. передавать в функцию, присваивать одному массиву другой и т.д. Но рано или поздно встает задача получить один конкретный элемент массива. Тогда нужно использовать следующий синтаксис:


$someArr = array(1, 2, 'Москва');

echo $someArr[2]; // Москва
echo $someArr[1]; // 2


В примере я не стал присваивать собственный индекс каждому элементу, а ограничился теми индексами которые создал PHP.

Теперь, что делать если нам нужно получить все элементы массива? Для этого в PHP есть специальная конструкция foreach.

Конструкция FOREACH

Как было сказано ранее, при работе с массивами в PHP лучше использовать стандартные функции и конструкциии языка, а не придумывать велосипед. Поэтому давайте познакомимся поближе с наиболее часто используемой конструкцией — foreach:


$someArr = array( 1, 2, 'Москва');
foreach($someArr as $index => $value) {
echo 'Индекс элемента массива = '. $index .', значение = '.$value; // выводит на экран значения всех переменных массива.

}


Как видите, все просто, сначала мы указываем имя конструкции — «foreach», затем в параметрах конструкции указываем имя массива, который нужно «перебрать» — «$someArr», а затем с помощью служебного слова «as», указываем какое какое имя будет у переменной содержащей индекс элемента массива — «$index» и значение элемента массива — $value.
Красивый дизайн квартиры foto в панельных домах Vanguard