takuya / php-genetator-array-access
make yield into an Array / ArrayAccess.
Requires (Dev)
- larapack/dd: ^1.1
- phpunit/phpunit: ^9.5
This package is auto-updated.
Last update: 2024-11-28 20:46:33 UTC
README
php / GeneratorArrayAccess
Make generator(yield) into ArrayAccess.
Example
<?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'
Why use.
Generator can foreach itself. but, cannot access as Array. This characteristic is against developers's intention. Like this.
Generator cannot be a array.
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 is not enough
Using \CachingIterator
is a common way, but make a problem
\CachingIterator cannot be a array.
This behaviour is very confusing.
$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.
With FullCache option, cached at initializing.
$node = new MyClass(); $elements = new \CachingIterator( $node->elements(), \CachingIterator::FULL_CACHE );// <= All Cached on constructor.
If generator is API call, It can spend a lot of time, caching time inevitable.
CachingIterator is useless. Everyone uses iterator_to_array()
instead.
iterator_to_array()
function has same problem ( load all, mess up Generator concept, get data when using ).
Dynamically get, make Unnecessary api call avoidable.
To solve that problem ,GeneratorArrayAccess cache dynamically.
$node = new MyClass(); $iter = new GeneratorArrayAccess($node->elements()); $iter[1]; //=> make cache $iter[0],$iter[1]; $iter[9]; //=> make cache $iter[0]...$iter[9]
Cache is able to reuse.
$node = new MyClass(); $iter = new GeneratorArrayAccess($node->elements()); // first access foreach($iter as $e){;;} // cache access with rewind. foreach($iter as $e){;;}
When use this.
Reduce WebAPI Call. without re-arrange code.
Current exists code.
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];
Use Generator.
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!.
Use 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**.
This class supports to make use of Generator(yield), Less code changed.
Limitations.
Infinite generator will be no response.
$generator = (function(){ while(true){ yield 'a';} })(); $iter = new GeneratorArrayAccess($generator); sizeof($iter);//=> infinite loop
Installation
from github
repository='php-generators-into-array-access' composer config repositories.$repository \ vcs https://github.com/takuya/$repository composer require takuya/$repository:master composer install
from composer
composer require takuya/php-genetator-array-access