如果你是Python或者其他语言的小伙伴,应该对生成器不陌生。但是很多PHP开发者可能并不知道生成器的作用。可能是因为生成器是PHP5.5.0引入的功能,或者生成器的作用不是很明显。然而,生成器函数确实非常有用。优点直接讲概念。估计你听完还是一头雾水,先说说优点吧,说不定会引起你的兴趣。那么生成器有哪些优点呢,具体如下:生成器会对PHP应用的性能产生很大的影响。PHP代码在运行时节省了大量内存,更适合计算大量数据。那么,这些神奇的功能是如何发挥作用的呢?让我们从一个例子开始。概念介绍首先抛开生成器概念的包袱,看一个简单的PHP函数:functioncreateRange($number){$data=[];对于($i=0;$i<$number;$i++){$data[]=time();}return$data;}这是一个很常见的PHP函数,我们在处理一些数组的时候经常会用到。这里的代码也很简单:我们创建一个函数。该函数包含一个for循环。我们将当前时间放入循环中的$data中。for循环执行后返回$data。下面没有结束,我们继续。让我们写另一个函数来循环打印出这个函数的返回值:$result=createRange(10);//这里我们调用我们上面创建的函数foreach($resultas$value){sleep(1);//这里暂停1秒,我们将跟进echo$value.'
';}让我们在浏览器中查看运行结果:这里很完美,没有任何问题。(当然看不到sleep(1)的效果)思考一个问题,我们注意到在调用函数createRange时,传给$number的值是10,一个很小的数字。假设,现在传一个值10000000(一千万)。然后,在函数createRange中,for循环需要执行1000万次。而1000万个值放在$data中,$data数组放在内存中。因此调用函数时会占用大量内存。在这里,发电机可以发挥作用。我们直接修改代码创建生成器,请注意:functioncreateRange($number){for($i=0;$i<$number;$i++){yieldtime();}}看这一段和刚才的代码一样,我们删除了数组$data,并没有返回任何东西,而是在time()之前使用了一个关键字yield来使用生成器。让我们再次运行第二段代码:$result=createRange(10);//这里我们调用上面创建的函数foreach($resultas$value){sleep(1);echo$value.'
';}我们奇迹般的发现,输出的值和第一次一样,不使用生成器就不一样了。这里的值(时间戳)间隔1秒。这里间隔一秒其实就是sleep(1)的结果。但是为什么第一次没有间隔呢?那是因为:当不使用生成器时:createRange函数中for循环的结果被快速放入$data并立即返回。因此,foreach循环是一个固定的数组。使用生成器时:createRange的值不是一次性快速生成的,而是依赖于foreach循环。foreach循环一次,fo??r执行一次。至此,您应该对生成器有所了解。深入理解生成器代码分析下面我们分析一下刚才的代码。函数createRange($number){for($i=0;$i<$number;$i++){yieldtime();}}$result=createRange(10);//这里我们调用上面创建的函数foreach($resultas$value){sleep(1);echo$value.'
';}我们来还原代码执行过程。先调用createRange函数,传入参数10,但是for值执行一次就停止,告诉foreach第一次循环可以使用的值。foreach开始循环遍历$result,首先sleep(1)进来,然后开始使用for给定的一个值执行输出。foreach准备第二个循环,在开始第二个循环之前,它会再次询问for循环。再次执行for循环,将生成的时间戳告诉foreach.foreach得到第二个值并输出。由于foreach中的sleep(1),for循环延迟1秒生成当前时间。因此,在整个代码执行过程中,参与循环的记录值始终只有一个,内存中的信息也只有一条。不管最初传入的$number有多大,由于并不是所有的结果集都是立即生成的,所以内存总是一个循环的值。概念理解到这里,你应该已经对什么是生成器有了大致的了解。下面说一下生成器原理。首先明确一个概念:生成器的yield关键字不是返回值。它的专业术语是输出值,它只是产生一个值。那么代码中的foreach循环是什么?实际上,PHP在使用生成器时,会返回一个Generator类的对象。foreach可以对对象进行迭代,对于每一次迭代,PHP都会通过Generator实例计算出下一次需要迭代的值。这样foreach就知道下次需要迭代的值了。而且在运行中for循环执行完后,会立即停止。等待下一个foreach循环再次请求下一个值,for循环将再次执行,然后再次立即停止。直到条件不满足才执行。实际开发应用很多PHP开发者不了解生成器,其实主要是不了解应用领域。那么,生成器在实际开发中有哪些应用呢?读取非常大的文件PHP开发经常需要读取大文件,比如csv文件,文本文件,或者一些日志文件。如果这些文件非常大,比如5G,这时候直接把所有内容读入内存计算是不现实的。这就是生成器派上用场的地方。看个例子:读取一个文本文件,我们创建一个文本文档,在里面输入几行文字来演示读取。$value){#code..echo$value.'
';}通过上图的输出我们可以看到该代码是完全正常的。但是,其背后的代码执行规则却完全不一样。使用生成器读取文件,第一次读取第一行,第二次读取第二行,以此类推,每次只加载一行文本到内存,大大减少了内存用法使用。这样就不用担心读G的文字了,可以像读小文件一样写代码了。最后给开发者推荐一款我们团队开发的网站导航:笔尖导航——用心做最简洁的网站导航可以自定义网站,可以自定义分类,可以标注颜色,可以自定义皮肤,可以自定义搜索网址,拖拽排序自定义插件模块
