php yield使用以及优点和场景


php yield使用以及优点和场景

php yield 使用,原生php在使用yield中还是比较少的,但还是很有学习的价值,如果后面去认识协程编程有很大帮助

优点

  1. 目前根据我使用的场景来看,yield协程操作可以改变执行流程,比如封装分批查询表中所有数据,查出目录下所有文件等等,外层只需要通过foreach来循环获得
  2. 避免一次性获取大批量数据节省内存消耗

1 php官网yield相关知识点

  1. yield正常使用

       function generate() {
         yield 1;
         yield 2;
         yield 3;
       }
       foreach(generate() as $row) {
         echo $row, "\n";
       }
       # 1
       # 2
       # 3
    
  2. yield 返回键值对

       function generate() {
         yield 88 => chr(1);
       }
       foreach(generate() as $key => $row) {
         echo "{$key} => {$row}", "\n";
       }
       # 88 => X
    
  3. 引用生成值

     function &gen_reference() {
         $value = 3;
    
         while ($value > 0) {
             yield $value;
         }
     }
     /* 
      * 我们可以在循环中修改$number的值,
      * 而生成器是使用的引用值来生成,
      * 所以gen_reference()内部的$value值也会跟着变化。
      */
     foreach (gen_reference() as &$number) {
         echo (--$number).'... ';
     }
    
  4. yield from使用

    php7.0之后引入的,如果你的环境是php5.6的话,直接return调用即可

       function generate() {
         yield 1;
         yield from generate2();
       }
       function generate2() {
         yield 2;
       }
       foreach(generate() as $row) {
         echo $row, "\n";
       }
       # 1
       # 2
    

2 项目中使用

  1. 数据库查询所有数据,使用yield来分页

       # 就拿最原始的数据库操作来示范
       # 生产中执行SQL最好先使用预处理
       public function getByChunk($sql, $limit=1000)
       {
           $offset = 0;
              
           while (true) {
               $tmpSql = $sql. " limit {$offset}, {$limit}";
               $rows = $this->getAll($tmpSql);
    
               # 没查出信息,相当于末页
               if (empty($rows)) {
                   return ;
               }
                  
               yield $rows;
    
               # 没有返回等量的数据,相当于末页了
               if (count($rows) < $limit) {
                   return ;
               }
               $offset += $limit;
               # 实际上如果分页过大查询效率也是大大降低
               # 如果sql中有ID,建议 使用last ID + order by ID asc来优化
           }
       }
    
  2. 迭代目录

       function dir($path)
       {
           try {
               $d = dir($path);
               while (false !== ($entry = $d->read())) {
                   if (in_array($entry , ['.' , '..'])) {
                       continue;
                   }
                   yield $entry;
               }
           } finally {
               $d->close();
           }
       }
    
  3. 循环处理返回大文件内容等

3 协程开发

yield本质就是在当前进程出让cpu执行权利给本进程其他地方执行, 如此我们可以做一些非阻塞操作,这样子大大提高cpu利用率。