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()方法就是进行指针移动的关键

为什么使用迭代器

  • 在处理具有大量数据的对象时,使用迭代器比数组更有效,因为在foreach迭代数组的时候会拷贝数组对象,而SPL迭代器通过内部封装每一次只会输出一个元素则更有效.
  • 延迟加载,迭代器在使用的时候能够加载仅仅需要的数据
  • 迭代器真正有用点在于用途比较广泛,能够通过实现迭代器接口创造出更多的数据结构

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

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";
}

总结:

  • 理解迭代器很容易,但是创建一个有意义的迭代器则不容易,这就类似于学习算法可能很容易,但如何实际运用则是另外一回事.
  • 通过SPL迭代器,避免了程序员自造轮子,同时也提供了更多的数据结构.
  • 至于使用数组还是迭代器,则要根据实际情况,比如从效率,可读性等方面衡量.
  • 通过SPL类和接口,PHP提供了更多扩展,这也是PHP越来越现代化的证明.

原文地址:https://www.cnblogs.com/usays/p/10640870.html

时间: 2024-10-09 07:19:49

PHP中for和foreach背后发生了什么和关于迭代器的理解的相关文章

Linux基础概念-----touch一个新文件背后发生的事情

一个普通用户在Shell下执行了一条命令,这背后发生了什么事情,是个人的一些总结,如果有不对的地方欢迎搭建指正,谢谢! touch /tmp/test.txt ####################################################################################### tom在Shell中执行这条命令,Shell将命令发给内核,并且判断命令是否存在,通过文件系统上的元数据判断tom是否有权限执行,内核从内存中加载出mkdir的指令

从点击Button到弹出一个MessageBox, 背后发生了什么(每个UI线程都有一个ThreadInfo结构, 里面包含4个队列和一些标志位)

思考一个最简单的程序行为:我们的Dialog上有一个Button, 当用户用鼠标点击这个Button时, 我们弹出一个MessageBox. 这个看似简单的行为, 谁能说清楚它是如何运行起来的,背后究竟发生了什么? 下面是我个人尝试的解答: (1)我们的鼠标点击事件到达设备的驱动程序, 驱动程序把消息放入系统硬件输入队列SHIQ(system hardware input queue). (2)通过系统的原始输入线程 RIT (raw input thread)把鼠标事件发送到对应的窗口.这里我

【翻译自mos文章】12c rac中,当脑裂发生时,哪个节点会幸存下来?

来源于: 12c: Which Node Will Survive when Split Brain Takes Place [1951726.1] 12c rac中,当脑裂发生时,哪个节点会幸存下来? 适用于: Oracle Database - Enterprise Edition - Version 12.1.0.2 and later Information in this document applies to any platform. 目的: 理解 从12.1.0.2开始,当脑裂发

ASP.NET MVC中分析淘宝网页发生乱码标题搞定方法

ASP.NET MVC中分析淘宝网页发生乱码标题搞定方法 近来正在分析淘宝中商品的信息,效果发生乱码,如: 原因便是中文字符格式发生冲突,ASP.NET MVC 默认采用utf-8,可是淘宝网页采用gbk.正在网上找了一下,最常常的搞定方法便是修改web.config:< system.web> ...... < globalization requestEncoding="gbk" responseEncoding="gbk" culture=&

java中异常注意问题(发生在多态是的异常问题)

/* 异常的注意事项: 1,子类在覆盖父类方法时,父类的方法如果抛出了异常,那么子类的方法只能抛出父类的异常或者该异常的子类. 2,如果父类抛出多个异常,那么子类只能抛出父类异常的子集. 简单说:子类覆盖父类,只能抛出父类的异常或者子类或者子集. 注意:如果父类的方法没有抛出异常,那么子类覆盖时绝对不能抛.子类不能抛出比父类多的异常.就只能try...catch */ class A extends Exception{ A(String msg){ super(msg); } } class

CSS中各种布局的背后(*FC)

CSS中各种布局的背后,实质上是各种*FC的组合.CSS2.1中只有BFC和IFC,CSS3 中还增加了FFC和GFC. 盒模型(BoxModel) 上图为W3C标准盒模型,另外还有一种IE盒模型(IE6以下),唯一的区别就是:前者width= content,后者width= content + padding + border 若要将IE盒模型转换为标准盒模型,需要在文档顶部加上<!DOCTYPEhtml>声明:很有意思的是,后来CSS3中也增加了box-sizing属性,box-sizi

培训中,好奇很重要,为什么多问几个有助于理解

培训中,为什么好奇很重要,为什么多问几个有助于理解 好奇,有一种表现形式,就是你对它感兴趣,觉得它好玩,觉得这个东西和别的东西不一样,同时也想知道它是怎么做到的,为什么会和别的不一样. 小时候,父亲常督促我“多问几个为什么能帮助你理解”.那个时候还小,完全不能理解“问为什么”和“理解”之间的关系.威严之下就哼哈答应,久而久之就当耳旁风了.不过即使现在他老人家也不能就这个问题给出一个很好的答案. 斯金纳箱实验 下面有个非常有意思的科学试验,可以很好的回答这个问题: 图1 斯金纳箱实验 准备实验 斯

【 c语言中无符号和有符号的加法运算】【深入理解】--【sky原创】

原文:[ c语言中无符号和有符号的加法运算][深入理解]--[sky原创] 第一题 #include<stdio.h> int main() { unsigned int a=6; int b=-20; printf("%d\n",a+b); (a+b)>6? puts(">6"):puts("<=6"); return 0; } 答案是:>6 第二题 #include<stdio.h> int m

javascript中的map, forEach

.map(fn)方法 1 var a=[2, 4, 6]; 2 a.map(function(d, i, arr){ 3 return {x:i, y:d*i, z:arr}; 4 }); 输出结果: 1 [{x:0, y:0, z:[2, 4, 6]}, 2 {x:1, y:4, z:[2, 4, 6]}, 3 {x:2, y:12, z:[2, 4, 6]}] 回调函数中传入的d是遍历数组的值, i是数组的索引, 整个数组也在第三个参数传进来 map会将原数组投射到一个长度一样的新数组中,新