设为首页收藏本站
网站公告 | 这是第一条公告
     

 找回密码
 立即注册
缓存时间15 现在时间15 缓存数据 当我买得起十几块钱一个的冰淇淋的时候,我已经不再天天想吃了。当我可以随便玩电脑而没人管的时候,我已经懒得打开电脑了。当我优秀得足够让你不会离我而去时,我已经不再非你不可了。

当我买得起十几块钱一个的冰淇淋的时候,我已经不再天天想吃了。当我可以随便玩电脑而没人管的时候,我已经懒得打开电脑了。当我优秀得足够让你不会离我而去时,我已经不再非你不可了。 -- 有没有人告诉你

查看: 1203|回复: 3

PHP迭代器和生成器用法实例分析

[复制链接]

  离线 

TA的专栏

  • 打卡等级:热心大叔
  • 打卡总天数:223
  • 打卡月天数:0
  • 打卡总奖励:3194
  • 最近打卡:2025-04-13 11:58:00
等级头衔

等級:晓枫资讯-上等兵

在线时间
0 小时

积分成就
威望
0
贡献
426
主题
392
精华
0
金钱
4484
积分
865
注册时间
2023-1-7
最后登录
2025-4-13

发表于 2023-2-12 22:37:59 | 显示全部楼层 |阅读模式
本文实例讲述了PHP迭代器和生成器用法。分享给大家供大家参考,具体如下:
迭代器
迭代器实际是一个实现了Iterator的类,可以用foreach进行遍历。
例如:
  1. <?php
  2. class Sample implements Iterator{
  3.   private $curIndex=0;
  4.   private $items=null;
  5.   public function __construct($_items) {
  6.     $this->items = $_items;
  7.   }
  8.   public function current (){
  9.     echo "current\n";
  10.     return $this->items[$this->curIndex];
  11.   }
  12.   public function key (){
  13.     echo "key\n";
  14.     return $this->curIndex;
  15.   }
  16.   public function next (){   
  17.       echo "next\n";
  18.       $this->curIndex++;
  19.   }
  20.   public function rewind (){
  21.       $this->curIndex = 0;   
  22.   }
  23.   public function send ( $value ){
  24.     if($value == "stop"){
  25.       $this->curIndex = null;
  26.     }
  27.   }
  28.   public function valid (){
  29.     echo "valid\n";
  30.     return isset($this->items[$this->curIndex]);
  31.   }
  32. }
  33. $sample = new Sample([1,2,3]);
  34. foreach ($sample as $k =>$v){
  35. }
复制代码
输出
  1.  valid current key next
复制代码
可以看到foreach 是先调用valid判断迭代器是否有效,然后再调用current获取当前值,同时调用next移动key到指向下一个值(输出key是因为 $k=>$v的缘故)。
生成器
让我们先看一下官方文档
  1. 生成器提供了一种更容易的方法来实现简单的对象迭代,相比较定义类实现 Iterator 接口的方式,性能开销和复杂性大大降低。
  2. 生成器允许你在 foreach 代码块中写代码来迭代一组数据而不需要在内存中创建一个数组, 那会使你的内存达到上限,或者会占据可观的处理时间。
  3. 相反,你可以写一个生成器函数,就像一个普通的自定义函数一样, 和普通函数只返回一次不同的是, 生成器可以根据需要 yield 多次,以便生成需要迭代的值。
  4. PHP 将会在每次需要值的时候调用生成器函数,并在产生一个值之后保存生成器的状态,这样它就可以在需要产生下一个值的时候恢复调用状态。
复制代码
下面是php官方文档中的示例
  1. <?php
  2. function gen_one_to_three() {
  3.   for ($i = 1; $i <= 3; $i++) {
  4.     //注意变量$i的值在不同的yield之间是保持传递的。
  5.     yield $i;
  6.   }
  7. }
  8. $generator = gen_one_to_three();
  9. foreach ($generator as $value) {
  10.   echo "$value\n";
  11. }
  12. var_dump($generator); //实际上是Generator对象
复制代码
如上,若把3修改成10000,对于$generator实际上没有区别,它只是保存了一个当前值(当然还有相关的内部状态,这里是为了简化),并没有产生10000个数。
从中可以看出生成器的优势在于减少内存的使用,在需要时才生成对应的值。
查看php文档,我们可以看到Generator实际也是Iterator的具体实现,yield调用时就是返回的Generator对象。
那么怎么理解迭代器和生成器的关系呢?
其实,生成器是迭代器的实现+yield,产生了生成器对象。
我们也可以自己定义一个类似yield的函数,如下:
  1. function myYeild(){
  2.   $args = func_get_args();
  3.   return new Sample($args);
  4. }
  5. $generator = myYeild(1,2,3);
  6. foreach ($generator as $value) {
  7.   echo "$value\n";
  8. }
复制代码
注意,我们的myYeild,是不能和php内置的yeild那么使用的,因为yeild会保存调用上下文,临时离开,并没有return。
这里只是类比一下。
既然yeild可以把普通的对象包装成generator,那么我们的iterator通过yeild也可以像Generator一样吗?
答案有点悲伤,yeild是把传入的值作为参数生成Generator实例,它并不知道我们的iterator。不过这样设计也是合理的,
以防我们自己的iterator不靠谱。
实际使用场合
      
  • 数据库遍历
可以结合游标,遍历数据库时,不需要一次返回所有数据,而是每次取一行。
  1. class AllUser implements \Iterator
  2. {
  3.   protected $index = 0;
  4.   protected $data = [];
  5.   public function __construct()
  6.   {
  7.     $link = mysqli_connect('192.168.0.91', 'root', '123', 'xxx');
  8.     $rec = mysqli_query($link, 'select id from doc_admin');
  9.     $this->data = mysqli_fetch_all($rec, MYSQLI_ASSOC);
  10.   }
  11.   //1 重置迭代器
  12.   public function rewind()
  13.   {
  14.     $this->index = 0;
  15.   }
  16.   //2 验证迭代器是否有数据
  17.   public function valid()
  18.   {
  19.     return $this->index < count($this->data);
  20.   }
  21.   //3 获取当前内容
  22.   public function current()
  23.   {
  24.     $id = $this->data[$this->index];
  25.     return User::find($id);
  26.   }
  27.   //4 移动key到下一个
  28.   public function next()
  29.   {
  30.     return $this->index++;
  31.   }
  32.   //5 迭代器位置key
  33.   public function key()
  34.   {
  35.     return $this->index;
  36.   }
  37. }
  38. //实现迭代遍历用户表
  39. $users = new AllUser();
  40. //可实时修改
  41. foreach ($users as $user){
  42.   $user->add_time = time();
  43.   $user->save();
  44. }
复制代码
      
  • 文件遍历
      一次读取一行  
  • 实现Iterator接口,让普通类可以使用foreach遍历。  
  • 协程,参见鸟哥则这篇文章。
注意:可以在生成器的函数前加"&",可以使用引用。在函数里直接return会终止生成器。
更多关于PHP相关内容感兴趣的读者可查看本站专题:《php常用函数与技巧总结》、《php字符串(string)用法总结》、《PHP数组(Array)操作技巧大全》、《PHP数据结构与算法教程》及《php程序设计算法总结》
希望本文所述对大家PHP程序设计有所帮助。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
晓枫资讯-科技资讯社区-免责声明
免责声明:以上内容为本网站转自其它媒体,相关信息仅为传递更多信息之目的,不代表本网观点,亦不代表本网站赞同其观点或证实其内容的真实性。
      1、注册用户在本社区发表、转载的任何作品仅代表其个人观点,不代表本社区认同其观点。
      2、管理员及版主有权在不事先通知或不经作者准许的情况下删除其在本社区所发表的文章。
      3、本社区的文章部分内容可能来源于网络,仅供大家学习与参考,如有侵权,举报反馈:点击这里给我发消息进行删除处理。
      4、本社区一切资源不代表本站立场,并不代表本站赞同其观点和对其真实性负责。
      5、以上声明内容的最终解释权归《晓枫资讯-科技资讯社区》所有。
http://bbs.yzwlo.com 晓枫资讯--游戏IT新闻资讯~~~

  离线 

TA的专栏

等级头衔

等級:晓枫资讯-列兵

在线时间
0 小时

积分成就
威望
0
贡献
0
主题
0
精华
0
金钱
21
积分
22
注册时间
2022-12-24
最后登录
2022-12-24

发表于 2024-12-27 10:09:52 | 显示全部楼层
感谢楼主,顶。
http://bbs.yzwlo.com 晓枫资讯--游戏IT新闻资讯~~~

  离线 

TA的专栏

等级头衔

等級:晓枫资讯-列兵

在线时间
0 小时

积分成就
威望
0
贡献
0
主题
0
精华
0
金钱
11
积分
2
注册时间
2023-8-8
最后登录
2023-8-8

发表于 2025-3-6 06:33:44 | 显示全部楼层
感谢楼主分享。
http://bbs.yzwlo.com 晓枫资讯--游戏IT新闻资讯~~~

  离线 

TA的专栏

等级头衔

等級:晓枫资讯-列兵

在线时间
0 小时

积分成就
威望
0
贡献
0
主题
0
精华
0
金钱
11
积分
2
注册时间
2023-10-31
最后登录
2023-10-31

发表于 2025-4-8 04:47:47 | 显示全部楼层
顶顶更健康!!!
http://bbs.yzwlo.com 晓枫资讯--游戏IT新闻资讯~~~
严禁发布广告,淫秽、色情、赌博、暴力、凶杀、恐怖、间谍及其他违反国家法律法规的内容。!晓枫资讯-社区
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

1楼
2楼
3楼
4楼

手机版|晓枫资讯--科技资讯社区 本站已运行

CopyRight © 2022-2025 晓枫资讯--科技资讯社区 ( BBS.yzwlo.com ) . All Rights Reserved .

晓枫资讯--科技资讯社区

本站内容由用户自主分享和转载自互联网,转载目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责。

如有侵权、违反国家法律政策行为,请联系我们,我们会第一时间及时清除和处理! 举报反馈邮箱:点击这里给我发消息

Powered by Discuz! X3.5

快速回复 返回顶部 返回列表