php生成器yield

一个生成器函数看起来像一个普通的函数,不同的是普通函数返回一个值,而一个生成器可以yield生成许多它所需要的值。

生成器提供了一种更容易的方法来实现简单的对象迭代,相比较定义类实现 Iterator 接口的方式,性能开销和复杂性大大降低。

<?php
function xrange($start, $limit, $step = 1) {
    if ($start < $limit) {
        if ($step <= 0) {
            throw new LogicException('Step must be +ve');
        }

        for ($i = $start; $i <= $limit; $i += $step) {
            yield $i;
        }
    } else {
        if ($step >= 0) {
            throw new LogicException('Step must be -ve');
        }

        for ($i = $start; $i >= $limit; $i += $step) {
            yield $i;
        }
    }
}

/*
 * 注意下面range()和xrange()输出的结果是一样的。
 */

echo 'Single digit odd numbers from range():  ';
foreach (range(1, 9, 2) as $number) {
    echo "$number ";
}
echo "\n";

echo 'Single digit odd numbers from xrange(): ';
foreach (xrange(1, 9, 2) as $number) {
    echo "$number ";
}

// 输出内容
Single digit odd numbers from range():  1 3 5 7 9
Single digit odd numbers from xrange(): 1 3 5 7 9

集合laravel与业务(更新uv)的例子:

<?php
/**
 * 数据修复
 * Author: sai
 * Date: 2019/9/19
 */
namespace App\Console\Commands;

use App\Models\StatisticModel;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Redis;

class DataStatistic extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'DataStatistic';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'DataStatistic';

    /**
     * Create a new command instance.
     *
     * @return void
     */
    public function __construct()
    {
        parent::__construct();
    }

    public function parseStr(...$param){
        $str = '';
        foreach ($param as $key => $value) {
            //处理数组
            if (is_array($value)) {
                $value = md5(json_encode($value));
            }
            $str .= $value;
        }

        return $str;
    }

    public function handle()
    {
        // 单独输出到updateChapter.log文件
        \Log::useFiles(storage_path().'/logs/data.log');
        $iTime = time();
        \Log::info('start', ['timestamp' => $iTime]);
        $i = 0;
        $ret =  $this->traverse();
        foreach ($ret as $v) {
            foreach ($v as $value) {
                $key = $this->parseStr('wx:', $value->wx_id);
                $count = (int) Redis::pfcount($key);
                // redis里的uv更大时更新,并记录更新前后数据
                if ($count > $value->uv) {
                    \Log::info('update id:'.$value->id, [$value->uv => $count]);
                    $i++;
                    (new StatisticModel(['hash_id' => $value->wx_id]))->where('id', $value->id)->update(['uv' => $count, 'update_time' => $iTime]);
                }
            }
        }
        // 记录更新时间与数量
        \Log::info('end', ['timestamp'=>time(), 'count' => $i,'interval' => time() - $iTime]);
        return true;
    }

    private function traverse()
    {
        $page = 3000;
        for ($i = 1; $i < 6; $i++) {
            $count = DB::table('wx_statistics_'.$i)->count();
            if ($count < 1) {
                // 记录进度
                \Log::info('update schedule', ['table success' => $i]);
                continue;
            }
            $num = ceil($count/$page);
            for ($j = 0; $j < $num; $j++) {
                $ret = DB::table('wx_statistics_'.$i)
                    ->select(['id', 'wx_id', 'uv'])
                    ->orderBy('id', 'asc')
                    ->skip($j*$page)
                    ->take($page)
                    ->get()
                    ->toArray();

                if (empty($ret)) {
                    continue;
                }
                yield $ret;
            }

            \Log::info('update schedule', ['table success' => $i]);
        }
        return true;
    }
}

php生成器yield
https://github.13sai.com/2019/09/20/199/
作者
13sai
许可协议