PHP 生成器的创建和使用学习笔记

1、概述

生成器是 PHP 5.5 引入的新特性,但是目测很少人用到它,其实这是个非常有用的功能。

生成器和迭代器有点类似,但是与标准的PHP迭代器不同,PHP生成器不要求类实现Iterator接口,从而减轻了类的开销和负担。生成器会根据需求每次计算并产出需要迭代的值,这对应用的性能有很大的影响:试想假如标准的PHP迭代器经常在内存中执行迭代操作,这要预先计算出数据集,性能低下;如果要使用特定方式计算大量数据,如操作Excel表数据,对性能影响更甚。此时我们可以使用生成器,即时计算并产出后续值,不占用宝贵的内存空间。

2、创建生成器

生成器的创建方式很简单,因为生成器就是PHP函数,只不过要在函数中一次或多次使用yield关键字。与普通的PHP函数不同的是,生成器从不返回值,只产出值。下面是一个简单的生成器实现:

function getLaravelAcademy() {
    yield www.111cn.net';
    yield 'Laravel学院';
    yield 'Laravel Academy';
}
很简单吧!调用此生成器函数时,PHP会返回一个属于Generator类的对象,这个对象可以使用foreach函数迭代,每次迭代,PHP会要求Generator实例计算并提供下一个要迭代的值。生成器的优雅体现在每次产出一个值之后,生成器的内部状态都会停顿;向生成器请求下一个值时,内部状态又会恢复。生成器内部的状态会一直在停顿和恢复之间切换,直到抵达函数定义体的末尾或遇到空的return语句为止。我们可以使用下面的代码调用并迭代上面定义的生成器:

foreach(getLaravelAcademy() as $yieldedValue) {
    echo $yieldedValue, PHP_EOL;
}
上面代码输出如下:

Laravel Academy

3、使用生成器

下面我们实现一个简单的函数用于生成一个范围内的数值,以此说明生成器是如何节省内存的。首先我们通过迭代器来实现:

function makeRange($length) {
    $dataSet = [];
    for ($i=0; $i<$length; $i++) {
        $dataSet[] = $i;
    }
    return $dataSet;
}

$customRange = makeRange(1000000);
foreach ($customRange as $i) {
    echo $i . PHP_EOL;
}
此时执行会报错,提示超出单个PHP进程内存限制(要为100万个数字提供内存空间):

memery-overflow-iterator

下面我们来改进实现方案,使用生成器实现如下:

function makeRange($length) {
    for ($i=0; $i<$length; $i++) {
        yield $i;
    }
}

foreach (makeRange(1000000) as $i) {
    echo $i . PHP_EOL;
}
再次执行就可以毫无压力的打印出结果,因为生成器每次只需要为一个整数分配内存。

此外,一个常用的使用案例就是使用生成器迭代流资源(文件、音频等)。假设我们想要迭代一个大小为4GB的CSV文件,而虚拟私有服务器(VPS)只允许PHP使用1GB内存,因此不能把整个文件都加载到内存中,下面的代码展示了如何使用生成器完成这种操作:

function getRows($file) {
    $handle = fopen($file, 'rb');
    if ($handle == FALSE) {
        throw new Exception();
    }
    while (feof($handle) === FALSE) {
        yield fgetcsv($handle);
    }
    fclose($handle);
}

foreach ($getRows($file) as $row) {
    print_r($row);
}
上述示例一次只会为CSV文件中的一行分配内存,而不会把整个4GB的CSV文件都读取到内存中。

4、总结

生成器是功能多样性和简洁性之间的折中方案,生成器只是向前进的迭代器,这意味着不能使用生成器在数据集中执行后退、快进或查找操作,只能让生成器计算并产出下一个值。迭代大型数据集或数列时最适合使用生成器,因为这样占用的系统内存最少。生成器也能完成迭代器能完成的简单任务,而且使用的代码更少。

时间: 2024-09-13 16:58:47

PHP 生成器的创建和使用学习笔记的相关文章

Akka学习笔记(一):创建Hello World工程

Akka学习笔记(一):创建Hello World工程 创建工程 使用IDEA,创建SBT工程,在build.sbt中添加akka依赖: name := "My Project" version := "1.0" scalaVersion := "2.10.4" resolvers += "Typesafe Repository" at "http://repo.typesafe.com/typesafe/relea

API Demos 2.3 学习笔记 (2)--创建第一个Android项目(Hello World!)

更多精彩内容,请点击阅读:<API Demos 2.3 学习笔记> 一.根据新建项目向导创建项目 启动Eclipse,选择"File"--"New"--"Project",打开新建项目向导.   展开"Android"项,选择"AndroidProject",单击"Next"按钮继续创建.      在"Projectname:"字段后填写项目名称&quo

MySQL学习笔记之创建、删除、修改表的方法_Mysql

本文实例讲述了MySQL学习笔记之创建.删除.修改表的方法.分享给大家供大家参考,具体如下: 创建表: create table users( id int, name varchar(64), sex bit(1), birthday date, Entry_date date, job varchar(32), salary float, resume text ); 1 添加列: alter table 表名 add 列名 数据类型 alter table users add image

《代码大全》学习笔记(1):欢迎进入软件创建世界

写在前面:          它山之石,可以攻玉!        <代码大全>是编程领域里的一本经典书籍,全书介绍了基本数据类型.变量命名.子程序和函数的编写.编程工具以及调试等内容.全书内容翔实.实用性强,特别适合刚入门或即将入门的程序员学习.该书对于良好编程习惯的养成具有极大的促进作用!         本系列文章是我在阅读<代码大全>过程中的学习笔记,基本上是按照原书的章节顺序进行编排的.在每一章的最后还有个人学习小结,供大家参考.希望大家能够从这本经典的书籍中受益,写出高质

我的Android进阶之旅------&amp;gt;Android中编解码学习笔记

编解码学习笔记(一):基本概念 媒体业务是网络的主要业务之间.尤其移动互联网业务的兴起,在运营商和应用开发商中,媒体业务份量极重,其中媒体的编解码服务涉及需求分析.应用开发.释放license收费等等.最近因为项目的关系,需要理清媒体的codec,比较搞的是,在豆丁网上看运营商的规范 标准,同一运营商同样的业务在不同文档中不同的要求,而且有些要求就我看来应当是历史的延续,也就是现在已经很少采用了.所以豆丁上看不出所以然,从 wiki上查.中文的wiki信息量有限,很短,而wiki的英文内容内多,

PHP学习笔记 (1) 环境配置与代码调试

一配置PHP环境 1.了解什么是PHP PHP("PHP: Hypertext Preprocessor",超文本预处理器的字母缩写) PHP,是英文超级文本预处理语言Hypertext Preprocessor的缩写.PHP 是一种 HTML 内嵌式的语言,是一种在服务器端执行的嵌入HTML文档的脚本语言,语言的风格有类似于C语言,被广泛的运用 2.PHP的背景和优势 PHP的发展背景 1).1994年由Rasmus Lerdorf创建,开始是一个简单的Perl语言编写的程序,用统计

Node.js 学习笔记之简介、安装及配置

 本文是Node.js学习笔记系列文章的第一篇,主要给大家讲解的是在Windows和Linux上安装Node.js的方法.软件安装版本以0.12.0为例.希望大家能够喜欢.     简单的说 Node.js 就是运行在服务端的 JavaScript. Node.js 是一个基于Chrome JavaScript 运行时建立的一个平台. Node.js是一个事件驱动I/O服务端JavaScript环境,基于Google的V8引擎,V8引擎执行Javascript的速度非常快,性能非常好. 谁适合阅

node.js学习笔记(9) 和谐模式

众所周知,ECMAScript 是一种开放的.国际上广为接受的脚本语言规范. 它本身并不是一种脚本语言.正如在 Web 应用程序中执行有用操作的 bean 集合(例如,Netscape 的 AWT)是 Sun 的 JavaBean 规范的一种实现一样,JavaScript 是 ECMAScript 规范的一种实现. 2015年6月17日,ECMA国际发布了EcmaScript2015,即EcmaScript6(以下简称ES6)草案的正式版.ES6是继ES5之后的一次主要改进,语言规范由ES5.1

php5学习笔记(转)

php5|笔记 作者: whhwq在phpv.net看到的感觉不错/*+-------------------------------------------------------------------------------+| = 本文为Haohappy读<<Core PHP Programming>> | = 中Classes and Objects一章的笔记 | = 翻译为主+个人心得 | = 为避免可能发生的不必要的麻烦请勿转载,谢谢 | = 欢迎批评指正,希望和所有