Статьи

Представляем стандартную библиотеку PHP 5

Большая часть шума вокруг PHP5 была сосредоточена на его новом объектно-ориентированном синтаксисе и возможностях, а также на сравнении с Java. Пока все это происходило, многообещающее название «Стандартная библиотека PHP» (SPL) незаметно проникло в основной дистрибутив PHP 5.

Хотя работа еще не завершена, текущее предложение Стандартной библиотеки PHP значительно увеличивает шансы на то, чтобы заставить разработчиков PHP договориться о чем-то (тем самым увеличивая шансы повторного использования кода). Это также может сделать ваш хитроумный интерфейс класса очень простым для использования другими людьми, поскольку расширение SPL позволяет «перегрузить» базовый синтаксис PHP и сделать объекты похожими на обычные массивы PHP.

В этом руководстве я познакомлю вас с функциональностью, доступной с расширением SPL и PHP5, с достаточным количеством примеров, чтобы вы могли начать. Имейте в виду: синтаксис PHP5 будет использоваться. Если вам нужно наверстать упущенное, попробуйте обзор Site5 по PHP5 .

Сегодняшние итерации:

  • Представляем SPL: что это такое?
  • Цикл: кто-то сказал «Итератор»?
  • Итерации предстают перед нами: «вау» фактор
  • Восхищение деревом: краткий обзор классов и интерфейсов SPL
  • Объекты в виде массивов: проще для дизайнера веб-страниц
  • Большое дело: почему тебе это нравится

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

Представляем SPL

«Стандартная библиотека PHP» — это расширение PHP, разработанное Маркусом Бергером, которое ( как говорится в руководстве ) «представляет собой набор интерфейсов и классов, предназначенных для решения стандартных задач». Как часть основного дистрибутива PHP5, он должен быть «всегда включен».

Если вы работали с PHP4, вы знаете, что есть несколько областей, в которых колеса постоянно изобретаются почти каждым новым проектом PHP. Стандартизация некоторых основных принципов — это хороший способ заставить петь PHP-разработчиков с одного листа, и это увеличивает шансы на то, что мы сможем повторно использовать код из Project X в Project Y.

Сегодня расширение SPL решает одну проблему: итераторы. Что делает реализацию SPL Iterator интересной, так это не только то, что она определяет стандарт для всех в PHP5, но также и то, что она «перегружает» определенные части синтаксиса PHP, такие как конструкция foreach и базовый синтаксис массива, облегчая работу с объекты ваших классов.

Зацикливание

Итак, что такое Итератор? В этом контексте «Итератор» относится к программному «шаблону проектирования», идентифицированному «Бандой четырех» в их революционной книге « Шаблоны проектирования» .

Цель итератора — «предоставить объект, который пересекает некоторую агрегатную структуру, абстрагируя предположения о реализации этой структуры».

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

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

Используя «нормальный» PHP, вы можете использовать следующее для цикла запроса MySQL:

// Fetch the "aggregate structure"  $result = mysql_query("SELECT * FROM users");   // Iterate over the structure  while ( $row = mysql_fetch_array($result) ) {  // do stuff with the row here  } 

Чтобы прочитать содержимое каталога, вы можете использовать:

 // Fetch the "aggregate structure"  $dh = opendir('/home/harryf/files');   // Iterate over the structure  while ( $file = readdir($dh) ) {    // do stuff with the file here  } 

И чтобы прочитать содержимое файла, вы можете использовать:

 // Fetch the "aggregate structure"  $fh = fopen("/home/hfuecks/files/results.txt", "r");   // Iterate over the structure  while (!feof($fh)) {     $line = fgets($fh);    // do stuff with the line here   } 

Взгляд на приведенные выше примеры показывает, что они очень похожи. Хотя каждый из них работает с ресурсом другого типа и использует функции PHP, специфичные для этого ресурса, мантра проста: «получить ресурс; перебрать содержимое».

Если бы каким-то образом можно было «абстрагировать» конкретные функции PHP от приведенных выше примеров и использовать вместо этого какой-то универсальный интерфейс, можно было бы сделать так, чтобы работа по циклированию над данными выглядела одинаково, независимо от типа ресурса. это было использовано. Без необходимости изменять цикл для другого источника данных, возможно, что код, в котором появляется цикл (возможно, функция, сгенерировавшая список HTML), может быть повторно использован в другом месте.

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

Это основная теория итераторов. Если вам интересно узнать больше, вы найдете отправную точку в C2 Wiki и Wikipedia . Больше мыслей от меня можно найти в phpPatterns по шаблону итератора и в Антологии PHP — Том II, Приложения .

Итерации предстают перед нами

Так что же такого интересного в итераторах SPL? Что ж, если вы написали больше, чем одну или две строки PHP, вы, вероятно, натолкнулись на конструкцию foreach , которая используется для облегчения работы с циклом в массиве:

 // A list of colors  $colors = array (    'red',    'green',    'blue',    );   foreach ( $colors as $color ) {    echo $color.'<br>';  } 

Разве не было бы неплохо, если бы все петли были такими простыми, независимо от того, что вы делали?

Как насчет этого?

 <?php  // A magic class... (explained in a moment)  class DirectoryReader extends DirectoryIterator {   function __construct($path) {    parent::__construct($path);  }   function current() {    return parent::getFileName();  }   function valid() {    if ( parent::valid() ) {      if ( !parent::isFile() ) {        parent::next();        return $this->valid();      }      return TRUE;    }    return FALSE;  }   function rewind() {    parent::rewind();  }  }   // Create a directory reader for the current directory  $Reader = new DirectoryReader('./');   // Loop through the files in the directory ?!?  foreach ( $Reader as $Item ) {  echo $Item.'<br>';  }  ?> 

Имя файла: directoryreader.php

Если вы на мгновение проигнорируете сам класс и посмотрите на последние несколько строк, вы увидите, что я использовал объект DirectoryReader прямо в цикле foreach. Я вытащил из него предметы, не вызывая ни один из его методов! Пока вы подчиняетесь определенным правилам (к которым я скоро вернусь), расширение SPL позволяет перебирать ваши собственные классы (при необходимости) точно так же.

На самом деле, с приведенным выше примером, я запрыгнул в глубокий конец! Давайте сделаем несколько шагов назад, чтобы я мог объяснить, что на самом деле здесь произошло.

Итерация с SPL

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

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

Расширение SPL определяет иерархию классов и интерфейсов . Некоторые из них уже будут загружены в вашу установку PHP5 (посмотрите, что вызывает get_declared_classes () ). Они соответствуют определениям интерфейса и класса, определенным здесь и здесь (файлы PHP, найденные здесь, со временем должны исчезнуть, как только у Маркуса будет время реализовать их в C). Некоторые из классов, найденных в каталоге примеров (с расширением .inc), также являются частью иерархии, но по умолчанию не загружаются; если вы хотите их использовать, вам нужно убедиться, что копии для включения находятся где-то в вашем пути включения PHP. Дополнительные примеры использования классов можно найти в тестах, а независимые примеры можно найти по адресу http://www.wiki.cc/php/PHP5#Iterators .

Хотя поначалу количество классов и интерфейсов в иерархии может быть пугающим, не паникуйте! Основное использование итераторов требует только одного интерфейса. Если вы новичок в идее интерфейсов, взгляните на это обсуждение интерфейсов в SitePoint.

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

Вернемся к примеру DirectoryReader. Как получилось, что я смог перебрать свой объект DirectoryReader, используя foreach? Волшебство исходит от класса, из которого я расширен, DirectoryIterator , который реализует интерфейс с именем Iterator, который определяется расширением SPL.

Любой класс, который я пишу, который реализует интерфейс Iterator, может использоваться в цикле foreach (обратите внимание, что эта статья объясняет, как это работает с точки зрения внутренних компонентов PHP). Интерфейс Iterator определяется следующим образом:

 interface Iterator extends Traversable {     /**    * Rewind the Iterator to the first element.    * Similar to the reset() function for arrays in PHP    * @return void    */    function rewind();     /**    * Return the current element.    * Similar to the current() function for arrays in PHP    * @return mixed current element from the collection    */    function current();     /**    * Return the identifying key of the current element.    * Similar to the key() function for arrays in PHP    * @return mixed either an integer or a string    */    function key();     /**    * Move forward to next element.    * Similar to the next() function for arrays in PHP    * @return void    */    function next();     /**    * Check if there is a current element after calls to rewind() or next().    * Used to check if we've iterated to the end of the collection    * @return boolean FALSE if there's nothing more to iterate over    */    function valid();   } 

Обратите внимание, что расширение SPL регистрирует интерфейс Traversable, от которого Iterator наследует Zend Engine, чтобы разрешить использование foreach. Интерфейс Traversable предназначен не для непосредственной реализации в PHP, а для других встроенных классов PHP (в настоящее время расширение SimpleXML делает это; расширение SQLite, вероятно, должно делать это, но прямо сейчас оно обращается непосредственно к Zend API). ,

Чтобы реализовать этот интерфейс, ваш класс должен предоставить все методы, определенные выше.

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

Для начала я определю класс для управления итерацией:

 /**  * An iterator for native PHP arrays, re-inventing the wheel  *  * Notice the "implements Iterator" - important!  */  class ArrayReloaded implements Iterator {     /**    * A native PHP array to iterate over    */  private $array = array();     /**    * A switch to keep track of the end of the array    */  private $valid = FALSE;     /**    * Constructor    * @param array native PHP array to iterate over    */  function __construct($array) {    $this->array = $array;  }     /**    * Return the array "pointer" to the first element    * PHP's reset() returns false if the array has no elements    */  function rewind(){    $this->valid = (FALSE !== reset($this->array));  }     /**    * Return the current array element    */  function current(){    return current($this->array);  }     /**    * Return the key of the current array element    */  function key(){    return key($this->array);  }     /**    * Move forward by one    * PHP's next() returns false if there are no more elements    */  function next(){    $this->valid = (FALSE !== next($this->array));  }     /**    * Is the current element valid?    */  function valid(){    return $this->valid;  }  } 

Имя файла: arrayreloaded.php

Обратите внимание на «реализует Iterator» в начале. Это говорит о том, что я согласен соблюдать «контракт» итератора и предоставит все необходимые методы. Затем класс предоставляет реализации каждого метода, выполняя необходимую работу с использованием встроенных в PHP функций массива (комментарии поясняют детали).

Есть несколько моментов дизайна Итератора, о которых стоит знать, когда вы пишете свой собственный. Методы-итераторы current() и key() можно вызывать несколько раз в течение одной итерации цикла, поэтому нужно быть осторожным, чтобы их вызов не изменил состояние итератора. В этом случае это не проблема, но, например, при работе с файлами может возникнуть соблазн использовать fgets () внутри метода current (), что продвинет указатель файла.

В противном случае помните, что метод valid () должен указывать, является ли текущий элемент действительным, а не следующий элемент. Это означает, что при циклическом переборе Итератора мы фактически продвигаем один элемент за пределы конца коллекции и обнаруживаем факт только при вызове valid() . Как правило, это будут методы next() и rewind() которые на самом деле перемещают Итератор и следят за тем, является ли текущий элемент действительным или нет.

Теперь я могу использовать этот класс следующим образом:

 // Create iterator object  $colors = new ArrayReloaded(array ('red','green','blue',));   // Iterate away!  foreach ( $colors as $color ) {  echo $color."<br>";  } 

Это очень удобно! За кулисами конструкция foreach вызывает определенные мной методы, начиная с rewind() . Затем, пока valid() возвращает TRUE , он вызывает current() для заполнения переменной $color и next() для перемещения итератора на один элемент вперед.

Как обычно для foreach, я также могу заполнить другую переменную значением, возвращаемым из метода key() :

 // Display the keys as well  foreach ( $colors as $key => $color ) {  echo "$key: $color<br>";  } 

Конечно, ничто не требует от меня использования foreach. Я мог бы вызывать методы прямо из моего кода, например так:

 // Reset the iterator - foreach does this automatically  $colors->rewind();   // Loop while valid  while ( $colors->valid() ) {     echo $colors->key().": ".$colors->current()."<br>";    $colors->next();   } 

Этот пример должен помочь вам увидеть, что foreach на самом деле делает с вашим объектом.

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

Восхищаясь деревом

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

Интерфейсы

  • Отслеживается : как упоминалось выше, это интерфейс Iterator для внутренних компонентов PHP. Если вы не пишете расширение, игнорируйте это.
  • Итератор : как вы уже видели, он определяет основные методы для итерации по коллекции.
  • IteratorAggregate : если вы предпочитаете реализовывать Iterator отдельно от вашего объекта «collection», реализация Iterator Aggregate позволит вам делегировать работу итерации отдельному классу, в то же время позволяя вам использовать коллекцию внутри цикла foreach.
  • RecursiveIterator : определяет методы, позволяющие выполнять итерацию по иерархическим структурам данных.
  • SeekableIterator : определяет метод для поиска в коллекции, которой управляет Итератор.
  • ArrayAccess : вот еще один волшебный интерфейс со специальным значением для движка Zend. Реализация этого позволяет вам рассматривать ваш объект как массив с обычным синтаксисом массива PHP (подробнее об этом ниже).

Классы

  • ArrayIterator : этот итератор может управлять как собственными массивами PHP, так и общими свойствами объекта (подробнее об этом позже).
  • ArrayObject : это объединяет массивы и объекты, позволяя вам перебирать их и использовать синтаксис массива для доступа к содержимому. См. «Объекты как массивы» ниже (мы вырастим наш собственный класс с аналогичным поведением).
  • FilterIterator : это абстрактный класс, который может быть расширен для фильтрации элементов, которые перебираются (возможно, удаляя ненужные элементы для поиска).
  • ParentIterator : при использовании ResursiveIterator ParentIterator позволяет отфильтровывать элементы, которые не имеют дочерних элементов. Если, например, у вас есть CMS, в которой документы могут быть размещены в любом месте под деревом категорий, ParentIterator позволит вам восстановить дерево, но отображать только «узлы категорий», исключая документы, которые отображаются под каждой категорией.
  • LimitIterator : этот класс позволяет вам указать диапазон элементов для Iterator, начиная со смещения ключа и указывая количество элементов для доступа с этой точки. Концепция аналогична предложению LIMIT в MySQL.
  • CachingIterator : он управляет другим Iterator (который вы передаете его конструктору). Он позволяет вам проверить, есть ли во внутреннем итераторе больше элементов, используя метод hasNext() , перед тем как перейти к next() методу next() . Лично я не уверен на 100% в названии; возможно LookAheadIterator будет более точным?
  • CachingRecursiveIterator : это в значительной степени то же самое, что и CachingIterator, но позволяет выполнять итерацию по иерархическим структурам данных.
  • DirectoryIterator : для итерации по каталогу в файловой системе этот итератор предоставляет набор полезных методов, таких как isFile() и isDot() которые экономят много хлопот.
  • RecursiveDirectoryIterator : этот класс позволяет выполнять итерации по структуре каталогов, чтобы вы могли спускаться в подкаталоги.
  • SimpleXMLIterator : это делает SimpleXML еще проще! В настоящее время лучшие примеры можно найти с помощью тестов SPL — см. Файлы, начинающиеся с «sxe_ *»
  • RecursiveIteratorIterator : это помогает вам делать такие крутые вещи, как «выравнивание» иерархической структуры данных, чтобы вы могли проходить по ней с помощью одного оператора foreach, сохраняя при этом знания об иерархии. Этот класс может быть очень полезен, например, для отображения меню дерева.

Чтобы увидеть его в действии, попробуйте использовать DirectoryTreeIterator (который расширяет RecursiveIteratorIterator), например так:

 $DirTree = new DirectoryTreeIterator('/some/directory');   foreach ($DirTree as $node) {    echo "$noden";  } 

Это обобщает основные классы и интерфейсы, которые сегодня определяет расширение SPL.

Объекты как массивы

Вы уже видели, как реализация интерфейса Iterator позволяет «перегружать» конструкцию foreach. Расширение SPL имеет еще несколько сюрпризов, начиная с интерфейса ArrayAccess. Реализация этого интерфейса с классом позволяет вам рассматривать объекты этого класса как массивы с точки зрения синтаксиса PHP.

Вот пример:

 /**  * A class that can be used like an array  */  class Article implements ArrayAccess {   public $title;   public $author;   public $category;   function __construct($title,$author,$category) {    $this->title = $title;    $this->author = $author;    $this->category = $category;  }   /**  * Defined by ArrayAccess interface  * Set a value given it's key eg $A['title'] = 'foo';  * @param mixed key (string or integer)  * @param mixed value  * @return void  */  function offsetSet($key, $value) {    if ( array_key_exists($key,get_object_vars($this)) ) {      $this->{$key} = $value;    }  }   /**  * Defined by ArrayAccess interface  * Return a value given it's key eg echo $A['title'];  * @param mixed key (string or integer)  * @return mixed value  */  function offsetGet($key) {    if ( array_key_exists($key,get_object_vars($this)) ) {      return $this->{$key};    }  }   /**  * Defined by ArrayAccess interface  * Unset a value by it's key eg unset($A['title']);  * @param mixed key (string or integer)  * @return void  */  function offsetUnset($key) {    if ( array_key_exists($key,get_object_vars($this)) ) {      unset($this->{$key});    }  }   /**  * Defined by ArrayAccess interface  * Check value exists, given it's key eg isset($A['title'])  * @param mixed key (string or integer)  * @return boolean  */  function offsetExists($offset) {    return array_key_exists($offset,get_object_vars($this));  }   } 

Имя файла: arrayaccess1.php

Четыре метода, которые начинаются с «смещения», определяются интерфейсом ArrayAccess, который я реализую.

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

function offsetSet($key, $value) { if ( array_key_exists($key,get_object_vars($this)) ) {

Я также ссылался на них косвенно, используя переменную, которая содержит их имена:

$this->{$key} = $value;

Этот пример становится интересным, когда вы видите, как теперь можно использовать этот класс:

 // Create the object  $A = new Article('SPL Rocks','Joe Bloggs', 'PHP');   // Check what it looks like  echo 'Initial State:<pre>';  print_r($A);  echo '</pre>';   // Change the title using array syntax  $A['title'] = 'SPL _really_ rocks';   // Try setting a non existent property (ignored)  $A['not found'] = 1;   // Unset the author field  unset($A['author']);   // Check what it looks like again  echo 'Final State:<pre>';  print_r($A);  echo '</pre>'; 

Помимо первой строки, в которой я создаю объект, код является допустимым синтаксисом для собственного массива PHP. Вот вывод:

 Initial State:   Article Object  (    [title] => SPL Rocks    [author] => Joe Bloggs    [category] => PHP  )   Final State:   Article Object  (    [title] => SPL _really_ rocks    [category] => PHP  ) 

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

function offsetGet($key) { if ( array_key_exists($key,get_object_vars($this)) ) { return strtolower($this->{$key}); } }

Это преобразовало бы все значения в нижний регистр.

Чтобы сделать объект итеративным, используя foreach или иным образом, теперь я могу воспользоваться классом SPL ArrayIterator в сочетании с интерфейсом IteratorAggregate .

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

Для начала я модифицирую первую строку класса Article, чтобы объявить реализацию интерфейса:

 class Article implements ArrayAccess, IteratorAggregate { 

Теперь мне нужно добавить еще один метод: getIterator() , который возвращает объект, использованный для итерации:

/** * Defined by IteratorAggregate interface * Returns an iterator for for this object, for use with foreach * @return ArrayIterator */ function getIterator() { return new ArrayIterator($this); }

После этого я могу просмотреть свойства, определенные в классе:

 $A = new Article('SPL Rocks','Joe Bloggs', 'PHP');   // Loop (getIterator will be called automatically)  echo 'Looping with foreach:<pre>';  foreach ( $A as $field => $value ) {  echo "$field : $value<br>";  }  echo '</pre>';   // Get the size of the iterator (see how many properties are left)  echo "Object has ".sizeof($A->getIterator())." elements"; 

Имя файла: arrayaccess2.php

Вот что он отображает:

 $A = new Article('SPL Rocks','Joe Bloggs', 'PHP');   // Loop (getIterator will be called automatically)  echo 'Looping with foreach:<pre>';  foreach ( $A as $field => $value ) {  echo "$field : $value<br>";  }  echo '</pre>';   // Get the size of the iterator (see how many properties are left)  echo "Object has ".count($A->getIterator())." elements"; 

Это дает мне:

 Looping with foreach:   title : SPL Rocks  author : Joe Bloggs  category : PHP   Object has 3 elements 

Обратите внимание, что я также смог использовать функцию count для объекта, чтобы узнать, сколько у него элементов. Это может позволить мне использовать другие конструкции цикла без необходимости вызывать методы Iterator:

 $size = count($A);  for($i = 0; $i < $size; $i++ ) {    echo $A[$i]."n";  } 

Что (пока) не работает — это применение функций массива PHP к объекту (вы получите жалобы на то, что он не является массивом). Однако, пока вы не выполняете проверку типов с помощью чего-то вроде is_array () , вы должны иметь возможность повторно использовать любую часть вашего собственного кода, которая была написана для ожидания массива.

Большое дело

Я надеюсь, что у вас появляется ощущение, что расширение SPL является чем-то «большим» с точки зрения облегчения жизни для разработчиков PHP. Лично я очень впечатлен тем, что уже предлагает SPL, и отдаю должное Маркусу Боргеру за то, что он сделал это возможным. Это также уладило некоторые сомнения, которые у меня были об интерфейсе в PHP5, доказав их полезность как механизма, с помощью которого мы можем указать контракт между движком PHP и кодом, написанным на PHP, позволяя изменить семантику синтаксиса PHP на большую. эффект.

Возможно, наиболее важным аспектом того, что SPL делает сегодня, является то, что он поощряет использование стандартов, во-первых, определяя набор API, которые «всегда включены» в PHP5 (так почему бы их не использовать?), И, во-вторых, с помощью дополнительная «морковь», позволяющая перегружать синтаксис PHP и такие конструкции, как foreach.

Предполагая, что мы все согласны использовать классы и интерфейсы, предоставляемые SPL, проекты могут начать сходиться на них. Например, рассмотрим HTML_TreeMenu , библиотеку PEAR, разработанную для обеспечения возможности создания древовидных меню на основе Javascript в HTML. Прямо сейчас, это оставляет изрядное количество работы разработчику. Вот пример того, что требуется для рисования дерева из структуры каталогов с HTML_TreeMenu сегодня:

 require_once 'HTML/TreeMenu.php';  $map_dir = 'c:/windows';  $menu  = new HTML_TreeMenu('menuLayer', 'images', '_self');  $menu->addItem(recurseDir($map_dir));   function &recurseDir($path) {    if (!$dir = opendir($path)) {        return false;    }    $files = array();    $node = &new HTML_TreeNode(basename($path), basename($path), 'folder.gif');    while (($file = readdir($dir)) !== false) {        if ($file != '.' && $file != '..') {            if (@is_dir("$path/$file")) {                $addnode = &recurseDir("$path/$file");            } else {                $addnode = &new HTML_TreeNode($file, $file, 'document2.png');            }            $node->addItem($addnode);        }    }    closedir($dir);    return $node;  }   echo $menu->printMenu(); 

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

 require_once 'HTML/TreeMenu.php';  $map_dir = 'c:/windows';  $menu  = new HTML_TreeMenu('menuLayer', 'images', '_self');   // Register the tree data structure  $menu->registerTree(new new RecursiveDirectoryIterator($map_dir);   echo $menu->printMenu(); 

Если под рукой нет RecursiveIterator, который бы подходил вашей проблеме, вы всегда можете реализовать свой собственный, оставив HTML_Treemenu воспользоваться подсказками типов, чтобы убедиться, что вы даете ему то, что ему нужно.

Больше стандартов, пожалуйста!

Вопрос в том, что еще можно стандартизировать? В конце концов, расширение называется «Стандартная библиотека PHP». После краткого обмена электронной почтой с Маркусом Бергером я с радостью сообщу о некоторых вещах, которые он имеет в виду на будущее (в зависимости от наличия времени и рук помощи):

  • Стандартные исключения, такие как RuntimeException и OutOfBoundsException (что-то эквивалентное встроенным исключениям Python, где исключения названы для проблемы, которую они будут использовать для пометки).
  • Некоторое понятие Design by Contract TM (которое, вероятно, будет вводить новые языковые конструкции, такие как requires() и ensures() , а также связанные исключения).
  • Больше реализаций шаблонов, где это возможно. Например, шаблон Observer может быть особенно хорошим кандидатом, но процитирую некоторые вопросы, которые есть у Маркуса:

    Проблема наблюдаемого в том, как это сделать без множественного наследования? Наблюдаемая вещь должна иметь контейнер наблюдателей. Но у нас есть только интерфейсы.

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

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

  • Некоторые понятия внедрения зависимостей (шаблон для управления объектами, которые зависят от других объектов). Для этой цели новый API отражения должен стать более доступным.

Если вы хотите услышать больше или поговорить с Маркусом напрямую, его можно найти на Международной конференции по PHP в ноябре этого года во Франкфурте, Германия, где он будет выступать с докладом по SPL.

Хватит с меня. Получите итерацию!