虞大胆的PHP之旅程序员

PHP中for和foreach背后发生了什么

2016-11-01  本文已影响305人  虞大胆的叽叽喳喳

在循环结构中,for是很常用的一种表达式,在学习python迭代器的时候,感觉很有意思,就反过来看看PHP中for和foreach是如何处理的

for和foreach简单描述

php中的for处理方式类似于c语言,只要expr2表达式为真,则循环会一直继续下去:

for (expr1; expr2; expr3)
    statement

php中的foreach主要是为了遍历数组和对象:
foreach开始执行的时候,数组内部的指针会自动指向第一个单元,每进行一次循环,数组和对象的内部指针为自动移动一位,尽量在移动的时候不要修改其值.

foreach (array_expression as $value)
    statement
foreach (array_expression as $key => $value)
    statement

迭代器

上述的forforeach描述很简单.

foreach能够循环任何迭代器对象,而这些对象不仅仅是数组,可以是任何类型的对象.
一个迭代器是一个对象,迭代器对象可能是一个数组,也可能是一个目录,甚至可以是数据库查询结果集.

SPL(the Standard PHP Library)通过内建的类,提供了很大数量的迭代器,从而让代码更有效,更可读.

The DirectoryIterator class

try {
    $iterator = new \DirectoryIterator($directory);
    foreach ($iterator as $info) {
        if (!$info->isDot() && $info->isFile()) {
            echo $info->__toString() . "\n";
        }
    }
} catch (Exception $e) {
    echo get_class($e) . ": " . $e->getMessage();
}

ArrayIterator

$arr = ["java", "python", "php"];
$iter = new ArrayIterator($arr);
foreach ($iter as $key => $value) {
    echo $key . ":  " . $value . "\n";
}

看一个另类的用法:

$val = ["shell", "python", "php"];
$arr = new \ArrayIterator($val);
while ($arr->valid()) {
    echo $arr->key() . " : " . $arr->current() . ":" . $arr->offsetGet($arr->key()) . PHP_EOL;
    $arr->offsetSet($arr->key(), "ok");
    $arr->next();
}
print_r($arr->getArrayCopy());

next()方法就是进行指针移动的关键

为什么使用迭代器

如何创建一个自定义迭代器

SPL迭代器类已经提供了很多功能的迭代器,PHP也提供了接口Iterator,IteratorAggregate让程序员创建自定义的迭代器类.

只要实现接口Iterator的五个方法就可以创建一个迭代器类,rewind(),current(), key(),next(),valid()

当迭代开始,PHP调用rewind()方法让指针回到数据集开始处,通过调用valid()方法检查数据是否可用,假如返回为true,则调用current()方法获取当前指针对应的值,同时key()能够获取到当前指针的key,最后再调用next()方法重复上述的流程.

class myIterator implements Iterator {
}

IteratorAggregate
Iterator接口比较适合于创建一个内部的迭代器,理想的情况下,使用IteratorAggregate更加适合创建一个外部的迭代器,只要实现getIterator()方法即可.

IteratorAggregateIterator的关系类似于容器和具体容器的关系

class myIteratorAggregate implements IteratorAggregate {

    protected $arr = array("php", "python", "shell");
    protected $type;

    function __construct($type = 1) {
        $this->type = $type;
    }

    public function getIterator() {
        if ($this->type == 1)
            return new ArrayIterator($this->arr);
        else
            return new myIterator($this->arr);
    }
}
$obj = new myIteratorAggregate ;
foreach ($obj as $v) {
    echo $v . "\n";
}

总结:

上一篇下一篇

猜你喜欢

热点阅读