takuya/php-generator-array-access

将生成器(yield)转换为Array / ArrayAccess。

1.0 2023-02-26 12:35 UTC

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