今天看了两块内容,一个是 Generator 还有一个是 Closures。这里面的话第一个比较简单,应该算是迭代器的变种,第二个闭包就比较麻烦了,以前就不是很懂,所以今天就仔细查了一些资料,争取对闭包能有更深入的了解。
Generator 首先讲下今天看的 Generator,以前学基础的时候确实没听过这个(看来确实学的太水了😂),了解了一下,听作者将,这个的优点就是耗资源少。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 <?php function myGenerator ( ) { yield 'asdfas' ; yield '1111' ; yield 'cccc' ; } foreach (myGenerator () as $yieldedValue ) { echo $yieldedValue , PHP_EOL; } ?>
上面就是这个 Generator 的用法,它的特性是,一开始不会将 yield 后面的值储存进内存中,只有当调用这个函数的时候,才会像 return 那样一个个取出来。这里就会有一个好处,所以作者提出这样一个问题。
Imagine you need to iterate a 4 GB comma-separated value (CSV) file and your virtual private server (VPS) has only 1 GB ofmemory available to PHP. There’s no way you can pull the entire file into memory.
这种情况下用数组什么的肯定爆掉嘛。这时候 Generator 的威力就体现出来了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 <?php function getRows ($file ) { $handle = fopen ($file , 'rb' ); if ($handle === false ) throw new Exception (); while (feof ($handle ) === false ) yield fgetcsv ($handle ); fclose ($handle ); } foreach (getRows ('data.csv' ) as $row ) print_r ($row ); ?>
因为 Generator 是一个一个yield这样读取的,所以在上面的那个方法,我们可以一次一次获取数据,而不是一下子将数据都获取过来。总而言之 Generator 就像 return 但它是一个可以多次使用的 return,是 PHP 里的一个语法糖。
Closure 这个就是一个很头疼的东西了。作者说在 PHP 里闭包就是匿名函数,我感觉以前又没好好学基础,如果他这样讲我就稍微理解了点,用法大概也清楚了点。
1 2 3 4 5 6 7 <?php $closure = function ($name ) { return printf ('Hello %s' , $name ); }; echo $closure ("robinson" );
这是一个简单的匿名函数的例子。
那匿名函数的优点在哪呢?
1 2 3 4 5 6 7 <?php function incrementNumber ($number ) { return $number + 1 ; } $numbersPlusOne = array_map ('incrementNumber' , [1 ,2 ,3 ]);echo ($numbersPlusOne );
array_map函数需要传入一个 callback 所以我们需要先定义一个函数然后传进去。
1 2 3 4 5 6 <?php $numbersPlusOne = array_map (function ($number ) { return $number + 1 ; }, [1 ,2 ,3 ]); print_r ($numbersPlusOne );
但是如果我们用了匿名函数的话,就不用像最上面那个例子那样再定义一个函数了。它在只需要使用一次函数的场景下十分有用和简洁。
我们在其他函数中要传入一个闭包要怎么做呢?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 <?php $closure = function ($name ) { return printf ('Hello %s' , $name ); }; echo $closure ("robinson" );function myCallback ( ) { echo "myCallback" ; } function sayHello ($callback ) { echo "hello world" ; call_user_func ($callback ); } sayHello ('myCallback' ); ?>
如果我们要将外面的值传进闭包,并且要同时改变他的值,这时候就要使用 &
和 use
了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 <?php function func ($val ) { $foo = function ( ) use (&$val ) { $val ++; }; $foo (); return $val ; } echo (func (0 ));
有时候我们要动态的给我们的类添加一个方法怎么办
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 <?php class Foo { private $name ; public function __construct ($name ) { $this ->name = $name ; } } $obj = new Foo ('robin' );$say = function ( ) { return "hello world" . $this ->name; }; $say = $say ->bindTo ($obj , $obj );echo ($obj ->say->__invoke ()); ?>
最好的办法是使用bindTo(),这个方法能将对象注入到我们的闭包中,从而实现在闭包中调用对象本身具有的值,给人一种动态增加方法的的错觉,但确实是很好的模拟了这种特性。
这次终于了解了bindTo()是怎么用的,以前看框架源码的时候一直不知道是干嘛的。