当前位置: 首页 > 后端技术 > PHP

PHP中Generator

时间:2023-03-29 19:48:35 PHP

的简单理解。Generator从PHP5.5开始,PHP增加了一个新的特性,那就是Generator,中文译为生成器。生成器可以简单的用来实现对象的迭代,先从官方的一个小例子说起。xrange在PHP中,我们都知道有一个函数叫range,用来生成一个等差数列的数组,然后我们就可以用这个数组来迭代foreach。具体是这样的。foreach(range(1,100,2)as$num){echo$num.PHP_EOL;}这段代码会输出一个等差数列,首项为1,末项为100,容差为2,它的执行顺序是这样的。首先,range(1,100,2)会生成一个数组,里面存放的是一个等差数列,然后在foreach中迭代这个数组。那么,问题来了,如果我要生成100万个数字怎么办?那么我们将占用数百兆内存。虽然现在内存很便宜,但是我们不能这样浪费内存。那么这个时候,我们的生成器就可以派上用场了。考虑下面的代码。函数xrange($start,$limit,$step=1){while($start<=$limit){yield$start;$开始+=$步骤;}}foreach(xrange(1,100,2)as$num){echo$num.PHP_EOL;}这段代码的结果和前面的代码完全一样,但是它的内部原理却颠倒了。我们刚才说了,在前面的代码中,range会生成一个数组,然后foreach会遍历这个数组,提取出某个值。但是在这段代码中,我们重新定义了一个xrange函数,在函数中,我们使用了一个关键字yield。我们都知道,当我们定义一个函数,希望它返回一个值时,我们使用return来返回。所以这个yield也可以返回一个值,但是和return是完全不同的。使用yield关键字,可以在函数运行时打断,同时保存整个函数的上下文,并返回一个Generator类型的对象。当对象的下一个方法执行时,会重新加载中断时的上下文,并继续运行,直到下一个yield出现。如果后面没有更多的yield,那么整个生成器就被认为结束了。这样,我们上面的函数调用就可以等价地写成如下。$nums=xrange(1,100,2);while($nums->valid()){echo$nums->current()."\n";$nums->next();}这里,$num是一个生成器对象。我们在这里看到三种方法,valid、current和next。当我们的函数执行完,后面没有yield中断,那么我们的xrange函数就执行完了,valid方法就会变成false。至于current,它会返回currentyield之后的值,也就是说generator的功能会被打断。然后在调用next方法后,函数会继续执行,直到下一次yield发生,或者函数结束。嗯,这里我们已经看到一个值是由yield“生成”并返回的。其实yield也可以写成$ret=yield;。和返回值一样,这里是在函数继续执行的时候给函数传递一个值,可以通过Generator::send($value)来使用。例如。函数总和(){$ret=yield;回声$ret。PHP_EOL;}$sum=sum();$sum->send('我是外面来的。');这样,程序就会打印出send方法,将字符串传进去。yield的两边可以同时调用。函数xrange($start,$limit,$step=1){while($start<=$limit){$ret=yield$start;$开始+=$步骤;回声$ret。PHP_EOL;}}$nums=xrange(1,100,2);while($nums->valid()){echo$nums->current()."\n";$nums->send($nums->current()+1);}这样使用时,send()可以返回下一个yield的返回值。其他Generator方法Generator::key()对于yield,我们可以这样使用yield$id=>$value,即我们可以通过key方法获取$id,当前方法返回$value。Generator::rewind()方法可以帮助我们重启生成器并保存上下文。同时会返回第一个yield返回的内容。第一次执行send方法时,会隐式调用rewind。Generator::throw()方法向生成器抛出异常。后记yield作为PHP5.5的一个新特性,我们使用了一种新的方法来高效地迭代数据。同时我们也可以使用yield来实现协程。