Boroda aka Hamster (fantaseour) wrote,
Boroda aka Hamster
fantaseour

Category:
  • Music:

PHP-SPL tricks

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

foreach( get_class_methods(DirectoryIterator) as $methodName)
{
  echo 
$methodName.'<br />';
}

Вот и сегодня я наткнулся на странность которая бы не потребовала много времени, будь под рукой описание

Работаем с двумерным массивом и рекурсивным итератором. Пусть имеется такой массив:

$array = array(
    array(
'name'=>'butch''sex'=>'male'),
    array(
'name'=>'fido''sex'=>'male'),
    array(
'name'=>'girly','sex'=>'female')
);

Конструкция foreach выдаст ожидаемый список всех значений массива:

$it=new RecursiveIteratorIterator(new RecursiveArrayIterator($array));
foreach(
$it as $key=>$value)
{
  echo 
$key.' -- '.$value.'<br />';
}
name -- butch
sex -- male
name -- fido
sex -- male
name -- girly
sex -- female

А вот while выдаст лишний элемент:

$it=new RecursiveIteratorIterator(new RecursiveArrayIterator($array));
while(
$it->valid()){
  echo 
$it->key().' -- '.$it->current().'<br/>';
  
$it->next();
}
0 -- Array
name -- butch
sex -- male
name -- fido
sex -- male
name -- girly
sex -- female

Наступает непонятко. Либо foreach в зависимости от ситуации делает next(), либо это rewind() ставит итератор в правильное начальное положение.

Перегрузив класс итератор получим ответ на наш вопрос:

class myrr extends RecursiveIteratorIterator
{
  public function 
next()
  {
    echo 
'next: ';
    
parent::next();
  }

  public function 
rewind()
  {
    
parent::rewind();
    echo 
'rewind: ';
  }
}

Конструкция foreach с этим итератором:

$it=new myrr(new RecursiveArrayIterator($array));
foreach(
$it as $key=>$value){
  echo 
$key.' -- '.$value.'<br />';
}

выдаст:

rewind: name -- butch
next: sex -- male
next: name -- fido
next: sex -- male
next: name -- girly
next: sex -- female
next:

Ну и вызвав $it->rewind() явно перед while добъемся правильного результата и здесь.

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

Вообще-то это скорее баг, чем фича -- новый итератор, должен быть в том же состоянии, что и после rewind()

Tags: development, php
Subscribe

  • Post a new comment

    Error

    default userpic

    Your reply will be screened

    When you submit the form an invisible reCAPTCHA check will be performed.
    You must follow the Privacy Policy and Google Terms of use.
  • 0 comments