对php中IteratorIterator的理解(代码示例)

来源:不言 发布时间:2018-10-26 17:07:51 阅读量:618

php之IteratorIterator个人理解

最近有重新开始捣鼓laravel的源码了,一年多没用实在是忘的差不多了,每次看都会从中学到很多,不懂就赶紧查手册。看到加载配置文件的部分(config/*.php),代码中大量使用spl类库和接口,今天就来扯一下IteratorIterator类,网上资料太少了,加上本人也不是怎么聪明,搞了好几天才有点眉目,以下是对它的个人理解。

IteratorIterator简介

IteratorIterator是一个迭代器包装器,当然它本身也是迭代器。它(假定它叫Outer)在实例化时必须传入一个实现了Traversable接口类型的迭代器实例(假定它叫Inner),当然你可以通过Outer的getInnerIterator方法获取到这个传入的迭代器参数Inner。你可以通过Outer的rewind(),next(),valid(),current()和key()方法对内部迭代器Inner进行处理。

重点理解

  1. 在遍历Outer的过程中,Outer只是将rewind(),next(),valid(),current()和key()的任何调用转发给内部迭代器Inner。

  2. Outer可以对转发返回的结果进行包装,但这并不会对Inner产生任何影响。

代码演示

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

<?php

namespace young;class InnerIterator implements \Iterator{

    private $dates;

    private $position;

 

    public function __construct($dates = [])

    {

        $this->dates    = $dates;

        $this->position = 0;

    }

 

    public function rewind()

    {

        echo 'call ' . __METHOD__ . '<br>';

        reset($this->dates);

    }

 

    public function valid()

    {

        echo 'call ' . __METHOD__ . '<br>';

        if ($this->position >= count($this->dates)) {

            # code...

            return false;

        }

        return true;

    }

 

    public function current()

    {

        echo 'call ' . __METHOD__ . '<br>';

        return $this->dates[$this->position];

    }

 

    public function key()

    {

        echo 'call ' . __METHOD__ . '<br>';

        return $this->position;

    }

 

    public function next()

    {

        echo 'call ' . __METHOD__ . '<br>';

        ++$this->position;

    }}class OuterIterator extends \IteratorIterator{

    function rewind()

    {

        echo __METHOD__ '<br>';

        return parent::rewind();

    }

     

    function valid()

    {

        echo __METHOD__ . '<br>';

        return parent::valid();

    }

     

    function current()

    {

        echo __METHOD__ . '<br>';

        return parent::current() . '_suffix';

    }

     

    function key()

    {

        echo __METHOD__ . '<br>';

        return parent::key() ;

    }

     

    function next()

    {

        echo __METHOD__ . '<br>';

        return parent::next() ;

    }

     

    function getInnerIterator()

    {

        echo __METHOD__ . '<br>';

        return parent::getInnerIterator();

    }}$tmpArr = array(

    '2018-10-01',

    '2018-10-02',

    //'2018-10-03',);$inner = new InnerIterator($tmpArr);$outer = new OuterIterator($inner);foreach ($outer as $key => $value) {

    # code...

    echo $key , '=>' , $value . '<hr>';}

运行结果:

1

young\OuterIterator::rewind

1

2

3

4

call young\InnerIterator::rewind

call young\InnerIterator::valid

call young\InnerIterator::current

call young\InnerIterator::key

1

2

3

4

5

young\OuterIterator::valid

young\OuterIterator::current

young\OuterIterator::key

0=>2018-10-01_suffix

young\OuterIterator::next

1

2

3

4

call young\InnerIterator::next

call young\InnerIterator::valid

call young\InnerIterator::current

call young\InnerIterator::key

1

2

3

4

5

young\OuterIterator::valid

young\OuterIterator::current

young\OuterIterator::key

1=>2018-10-02_suffix

young\OuterIterator::next

1

2

call young\InnerIterator::next

call young\InnerIterator::valid

1

2

3

4

5

young\OuterIterator::valid

 object(young\InnerIterator)#1 (2) {

[“dates”:“young\InnerIterator”:private]=> array(2) { [0]=>

string(10) “2018-10-01” [1]=> string(10) “2018-10-02” }

[“position”:“young\InnerIterator”:private]=> int(2) }

结果分析

Outer的每次迭代会先调用自己的方法,然后转发给Inner。
Outer内部方法的返回值都是基于Inner的相对于方法的返回。
你可以在Outer内方法对Inner的返回值做逻辑处理。
当Inner的valid返回false的时候,外层的Outer也将停止迭代。
Outer内的方法对返回值的修改并不会影响Inner。
Outer内的方法在迭代过程中并不会执行getInnerIterator方法,它只是一个获取Inner方法的调用接口。

一点补充

之前在网上翻阅资料时会看到这样的疑惑

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

//假如这里还是使用了上面的两个类代码

<?php

namespace young;

class InnerIterator implements \Iterator

{

    //code 这里的代码假如和上面的一样

}

class OuterIterator extends \IteratorIterator

{

    //code 这里的代码假如和上面的一样

}

$outer->valid();           //false

$outer->current();         // _suffix  问题一

$outer->rewind();   

$outer->valid();            //true

$outer->current();         //2018-10-01_suffix

$outer->next()

$outer->rewind();

$outer->current();         //2018-10-02_suffix  问题二

这里有两个问题,

  1. 问题一,为什么当前current没值,valid为false

  2. 问题二,问什么next后rewind之后,current是第二个值

从上面的运行结果可知,$outer不执行rewind,$inner也不会执行,所以valid返回false,current为null,_suffix只是自己拼接上的。
第二个问题也是很奇怪的,也是刚刚发现的,$inner的指针只要前进了,就回不去了,也就是说 $inner的position属性在第一次next之后变成1了,即使你rewind,position还是1,这个有点蒙蔽啊。。。
所以如果你进行了$outer的遍历操作,第二遍是没值输出的,即使第二遍也执行了rewind操作,但是这个操作在第二遍压根就没用~~~


标签: PHP
分享:
评论:
你还没有登录,请先