takuya / php-generator-array-access
将生成器(yield)转换为Array / ArrayAccess。
1.0
2023-02-26 12:35 UTC
Requires (Dev)
- larapack/dd: ^1.1
- phpunit/phpunit: ^9.5
This package is auto-updated.
Last update: 2024-09-28 20:25:28 UTC
README
php / GeneratorArrayAccess
将生成器(yield)转换为ArrayAccess。
示例
<?php // generators by yield. $generator = (function(){foreach (['x'.'y','z'] as $e){ yield $e;}})(); // Using with new. use Takuya\Php\GeneratorArrayAccess; $iter = new GeneratorArrayAccess($generator); // Access as Array. $iter[0]; #=> 'x' $iter[1]; #=> 'y' $iter[2]; #=> 'z'
为什么要使用。
生成器可以对自己进行foreach,但不能作为数组访问。这种特性与开发者的意图相悖。如下所示。
生成器不能作为数组。
class MyClass{ public function elements(){ foreach ($this->paths[] as $path){ yield get_something($path); } } } $node = new MyClass(); // Generator can Access foreach foreach ($node->elements() as $item) { // something. } // but Cannot access as Array $first = $node->elements()[0]; //=> Error
CachingIterator不够用
使用 \CachingIterator
是一种常见方法,但会带来问题
\CachingIterator 不能作为数组。
这种行为非常令人困惑。
$node = new MyClass(); $elements = new CachingIterator($node->elements()) // CachingIterator cannot access Directory, before cached. $first = $elements[1]; //=> BadMethodCallException // after caching, CachingIterator can access as Array. foreach ($elements as $e){;;} $first = $elements[1]; //=> not null.
使用FullCache选项,在初始化时进行缓存。
$node = new MyClass(); $elements = new \CachingIterator( $node->elements(), \CachingIterator::FULL_CACHE );// <= All Cached on constructor.
如果生成器是API调用,它可能会花费很多时间,缓存时间不可避免。
CachingIterator没有用。每个人都使用 iterator_to_array()
代替。 iterator_to_array()
函数有相同的问题(加载所有,打乱生成器概念,使用时获取数据)。
动态获取,避免不必要的API调用。
为了解决这个问题,GeneratorArrayAccess动态缓存。
$node = new MyClass(); $iter = new GeneratorArrayAccess($node->elements()); $iter[1]; //=> make cache $iter[0],$iter[1]; $iter[9]; //=> make cache $iter[0]...$iter[9]
缓存可以复用。
$node = new MyClass(); $iter = new GeneratorArrayAccess($node->elements()); // first access foreach($iter as $e){;;} // cache access with rewind. foreach($iter as $e){;;}
当使用此功能时。
减少WebAPI调用。无需重新排列代码。
现有的代码。
function my_list_items(){ foreach( $api->call('list_item') as $id){ $list[]=$api->call('get_item', $id); } return $list; } $items = $my_list_items(); $item = $items[0];
使用生成器。
function my_list_items(){ foreach( $api->call('list_item') as $id){ $item = $api->call('get_item', $id); yield $item; } } $items = $my_list_items(); $item = $items[0];//<= No Code changed. Becomes ERORR!.
使用GeneratorArrayAccess
function my_list_items(){ return new GeneratorArrayAccess((function(){ foreach( $api->call('list_item') as $id){ $item = $api->call('get_item', $id); yield $item; } })()); } $items = $my_list_items(); $item = $items[0];//<= No Code changed. **No Error**.
此类支持使用生成器(yield),代码更改较少。
局限性。
无限生成器将无响应。
$generator = (function(){ while(true){ yield 'a';} })(); $iter = new GeneratorArrayAccess($generator); sizeof($iter);//=> infinite loop
安装
从GitHub
repository='php-generators-into-array-access' composer config repositories.$repository \ vcs https://github.com/takuya/$repository composer require takuya/$repository:master composer install
从Composer
composer require takuya/php-genetator-array-access