与标准的PHP迭代器不同,PHP天生器不哀求类实现Itereaor(不知道这个是什么?看补充迭代器部分)接口,从而减轻了类的包袱。如果标准的PHP迭代器常常在内存中实行迭代操作,这要预先打算出数据集,性能低下;如果利用特定的办法打算大量数据,对性能的影响愈甚。此时我们可以利用天生器,及时打算并产出后续值,不占用宝贵的内存资源。
大略补充迭代器
很多小伙伴不知道迭代器是什么,也便是Itereaor接口是什么。
PHP官方简介:可在内部迭代自己的外部迭代器或类的接口。(太抽象,看不懂?)
个人理解:高等foreach循环,能够让工具像数组一样循环。
实在foreach也能循环工具,差异在于:如果你的类并实现了Iterator接口,那么你的这个类工具便是ZEND_ITER_OBJECT,否则便是ZEND_ITER_PLAIN_OBJECT。对付ZEND_ITER_PLAIN_OBJECT的类,foreach会通过HASH_OF获取该工具的默认属性数组,然后对该数组进行foreach,而对付ZEND_ITER_OBJECT的类工具,则会通过调用工具实现的Iterator接口干系函数来进行foreach。
看不懂没紧要,基本你也不会去用,哈哈哈,这里只是想解释一个问题,不管你利用foreach还是自己创建的迭代器,你要循环的数据是预师长西席成的,这个数据会加载到内存,供应给迭代器循环输出,那么这个数据如果超过最大内容限定,会提示内存不敷,当然你可以利用 ini_set(39;memory_limit', '内存大小');来临时改变内存,但是如果还是不足怎么办,例如:我现在有个日志文件,大小是5G,做事器的内存2G,你全开都不足啊,哈哈哈哈哈,怎么办呢?天生器就能给我办理这个问题,哈哈哈,大部分我利用天生器也是读文件在用。
把稳:PHP天生器不能知足所有迭代操作的需求,由于如果不查询,天生器永久不知道下一个要迭代的值是什么,这里提到一个开拓中常碰着的问题来举例:数据库操作,有时候对大批量数据进行处理,如果把数据全部查询出来,很多小伙伴会碰着内存溢出,那么多数据保存在内存中,肯定不敷啊,这里的办理方案便是分块拿,每次拿1000,用完再拿1000,这个办理方案在各个框架都有,例如laravel中等chunk(),tp5中也是chunk(),分块拿,小伙伴可以定位到这个chunk(),里面是do{}while{}循环在处理,那么问题来了,能否用本日我们探究的天生器来办理呢?答案是no,至于为什么,由于天生器永久不知道下一个要迭代的值是什么,这里对数据库的操作,我们只能采纳数据拿出才能办理,难道你打算每次读取一条,那么这样数据库资源更大,不建议。
创建天生器天生器的创建很大略,只是一个PHP函数,利用yield关键字。与普通的PHP函数不同的是,天生器从不返回值,只产出值,和return是有差异的。
<?php
function myGenerator() {
yield 'test1';
}
定义天生器是很随意马虎的,就和定义函数一样,我们函数利用return 返回,换成yield 直接产值就好,大略吧,最紧张我们来看看天生器常见的利用吧。
利用天生器下面的代码是我常利用天生器的案例,欢迎在其他地方也能利用天生器的小伙伴反馈,共同发展。
<?php// 定义一个天生器function readeFile($file){ $handle = fopen($file, 'r');// 只读打开文件得到文件资源 if ($handle == false) { // 打开失落败抛出非常 throw new Exception(); } while (feof($handle) === false) {// 判断是否到文件末了 yield fgets($handle); // 读取一行 } fclose($handle);// 关闭文件资源文件}$file = 'text.txt';// 逐行读取foreach (readeFile($file) as $row) { print_r($row);}
当text.txt文件大于你的内存时 也不会出问题哟!
闭包
闭包和匿名函数是PHP5.3.0中引入,这两个特性是仅次于命名空间利用最多的吧,或多或少,你在开拓中肯定利用了的,这两个特性很有必要去节制(好用+利用频率超高,上面提到的天生器不用也没事儿,但是这两个特性不能错过)。
闭包是指在创建时封装周围状态的函数。
匿名函数是没有名称的函数。
理论上闭包和匿名函数两个不同的函数,但是在PHP中实在一样,虽然闭包和匿名函数的利用和普通函数相同,但是闭包和匿名函数是工具,你没有看错,他们是Closure类的实例,伪装成函数的工具,哈哈哈哈哈,吓到了没。
创建闭包
先来看大略的闭包利用:
<?php$closure = function ($name) { return "hello " . $name;};echo $closure('phper');
输出结果是:hello phper
我们利用闭包最常见的是结合PHP自带的一些函数,会用到回调函数,比如array_map(),preg_replace_callback(),直接看写法,比较大略:
<?php// 写法一// 匿名函数直接放在参数位置$res1 = array_map(function ($value) { return $value + 1;}, [1, 2, 3]);var_dump($res1);// 写法二// 定义函数function doMap($value){ return $value + 2;}// 函数名当参数$res2 = array_map('doMap', [1, 2, 3]);var_dump($res2);
输出结果分别是:
array(3) { [0]=> int(2) [1]=> int(3) [2]=> int(4) }
array(3) { [0]=> int(3) [1]=> int(4) [2]=> int(5) }
还有一些PHP自带函数利用回调函数,欢迎小伙伴们留言整理,哪些函数会用到匿名函数,我先举例几个吧:
array_map(),preg_replace_callback(),array_diff_uassoc(),array_intersect_uassoc() 我只选了几个数组干系的函数,还有很多,欢迎小伙伴们留言,请顺带阐明下函数的用法,方便大家利用嘛,哈哈哈。
那么问题又来了,上面讲的都是PHP自带的函数利用匿名函数来处理,如何自己来写或者说开拓中我们怎么自己来写,那就让我们来提升下吧,用上面提及到的 laravel中等chunk() 这个方法来举例,如何利用,只是大略的仿照,开拓中利用根据自身场景!
<?phpclass Test{ // 仿照数据库只有4页数据 private $page = 4; // 仿照数据库中4页数据 private $dataBase = [ 1 => [['name' => 'test1', 'age' => 12], ['name' => 'test2', 'age' => 8]], 2 => [['name' => 'test3', 'age' => 13], ['name' => 'test4', 'age' => 15]], 3 => [['name' => 'test5', 'age' => 4], ['name' => 'test6', 'age' => 23]], 4 => [['name' => 'test7', 'age' => 5], ['name' => 'test8', 'age' => 12]], ]; // 获取结果 public function getResult($page) { $dataBase = $this->dataBase; return $dataBase[$page] ?? []; } // 仿照分块处理数据 public function chunk($page, callable $callback) { do { $result = $this->getResult($page); if (!$result) break; $callback($result); $page++; } while ($page <= $this->page); return true; }}$test = new Test();// 从第几页开始取$test->chunk(1, function ($data) { foreach ($data as $k => $v) { $str = 'name: ' . $v['name'] . '-' . 'age: ' . $v['age'] . "\n"; // 直接输出 echo $str; // 或者写入文件 //file_put_contents('text.txt', $str, FILE_APPEND); // 想怎么处理 你自己看着办吧 哈哈哈哈哈 }});
利用相称大略吧,合理利用闭包的写法,会提升代码质量
由于闭包的东西比较多,下篇文章我们将连续深入学习哟!
附上代码demo: https://github.com/lirui310/demo-generator
后续会连续更新,感兴趣的小伙伴可以收藏下哟!
欢迎有问题或者项目开拓有问题的小伙伴(妹子优先)添加微信:wxmm686800,共同发展!
不好意思可以邮箱联系:lirui310@aliyun.com