基本迭代器类和字符串遍历


Basic Iterator class, and string traversal

我知道这是一个简单的问题,但我只是无法弄清楚顺序在哪里出错。

<?php
class StringIterator implements 'Iterator
{
private $_string;
private $_length;   
private $_position;

public function __construct($string)
{
    if(empty($string))
    {
        throw new 'InvalidArgumentException(sprintf('The specified string is empty'));
    }//end if
        $this->_string = $string;
        $this->_length = strlen($this->_string);
        $this->rewind(); //setting the initial position instead of having it all over the place.
}//end func 
public function current()
{
 return $this->_string[$this->_position];
}//end func
public function key()
{
    return $this->_position;
}//end func

public function rewind()
{
    $this-> _position = -1;
}//end func

public function next()
{
    $this-> _position++;
}//end func

public function valid()
{   //why is it that your doing this instead of...
/*
*   return isset(this->_string[this->_position]);
*
*
*/
    return $this->_position < $this->_length;
}//end func

}//结束类

TEST CLASS
<?php
require_once __DIR__. '/../src/Iterators/StringIterator.php';
class StringIteratorTest extends PHPUnit_Framework_TestCase
{
    //each method must begin with TEST
public function testInitializing()
{
    $iterator = new 'Iterators'StringIterator("Hello World");
    $this->assertEquals(true,$iterator->valid()); 

}//end func
/**
*   @expectedException InvalidArgumentException
*/
public function testInitException()
{
$iterator = new 'Iterators'StringIterator("");
}//end func

public function testTraverse()
{
    $string ="Hello World";
    $iterator = new 'Iterators'StringIterator($string);
    $count =0;
    $iterator->rewind();
    //test to make sure the next() runs.

    //The iterator interface defines the method Key key()= $key
    //Iterator::current() = $char (gets the current value at the position)
    foreach($iterator as $key=>$char)
    {
        $this->assertEquals($count,$key);
        $this->assertEquals($string[$count],$char);
        ++$count;
         $this->next();
    }//end 4e
}//end func
//tests that the internal pointer (it) is at a valid position in that container that is being iterated
public function testValid()
{
$iterator = new 'Iterators'StringIterator($string);
}//end func
//tests the rewind method back to the start of the container.
public function testRewind()
{
$string="Bye";
$iterator = new 'Iterators'StringIterator($string); 

for( $i = 0; $i< strlen($string) + 1; ++$i){
$iterator->next();
}//end for
$this->assertEquals(false,$iterator->valid());
$iterator->rewind();
$this->assertEquals(true,$iterator->valid());
}

}

有问题的问题:当我运行测试(phpunit test)时,它指出实际测试组件的current() (return line)foreach循环中存在错误

foreach($iterator as $key=>$char)
{
    $this->assertEquals($count,$key);
    $this->assertEquals($string[$count],$char);
    ++$count;
    $this->next();
}//end 4e

从我的研究中,我知道这与我在foreach循环中接下来调用的顺序有关,我只是可以确切地弄清楚它需要是什么。

这里似乎有很多错误:

  • 你在StringIteratorTest::testTraverse()内打电话给$this->next().这种方法没有这种next()方法。该方法属于StringIterator类。这应该是一个致命错误。
  • 即使此代码 StringIterator 类中运行,您仍然不需要从 foreach 循环中调用next()foreach调用所有Iterator定义的方法本身。这就是重点。在foreach内调用next()只会产生跳跃位置的效果。
  • 您的rewind()方法不正确。它将位置设置为负值。字符串中没有负位置。如果你要为此调用current(),你会得到一个错误,因为它试图调用$_string[-1],这不存在。
  • 您的valid()方法也不正确,因为它只检查仓位是否超出上限,而不是下限。这就是为什么即使您的rewind()方法将位置设置为无效状态,valid()也会返回TRUE
  • 您的testValid()方法应该已捕获此问题,但该函数实际上并未测试 valid() 方法。它只是创建一个新对象,对它不做任何事情。
  • 您的测试方法在testRewind()方法中很糟糕。与其检查valid(),不如调用current()并检查它是否返回"B",这是字符串中的第一个字符。rewind() 方法的主要功能是将对象的内部指针重置回起点,因此您应该显式测试它。