phpy
phpy copied to clipboard
[ Feature ] Support for PHP generators
Is it possible to add support for PHP generators to be passed to Python?
Per example, pandas dataframe object could work with generators for large datasets...
You can implement a Python iterator class on the PHP side like this:
declare(strict_types=1);
namespace YourNamespace;
use Closure;
use Exception;
use Generator;
#[\PyInherit('Iterator', 'typing')]
class Iterator extends \PyClass
{
protected Generator $generator;
/**
* @param Generator|Closure $generator
* @throws Exception
*/
public function __construct(
Generator|Closure $generator
)
{
parent::__construct();
if ($generator instanceof Closure) {
$generator = $generator();
if (!$generator instanceof Generator) {
throw new \InvalidArgumentException('Closure must return a Generator. ');
}
}
$this->generator = $generator;
}
public function __iter__()
{
return $this->self();
}
public function __next__()
{
if (!$this->generator->valid()) {
return null;
}
$value = $this->generator->current();
$this->generator->next();
return $value;
}
public function __invoke(): ?\PyIter
{
$res = $this->self();
return $res instanceof \PyIter ? $res : null;
}
}
\PyClass::setProxyPath(__DIR__);
Then, make a slight tweak to the proxy generated by phpy—specifically, in the implementation of next, add logic to throw a StopIteration:
import typing
class workbunny_phporc_iterator(typing.Iterator):
def __init__(self, _this):
self.__this = _this
_this.set('_super', super())
_this.set('_self', self)
_this.call('__init')
def __iter__(self, ):
return self.__this.call('__iter__', )
def __next__(self, ):
res = self.__this.call('__next__', )
if res == None:
raise StopIteration
return res
def __init(self, ):
return self.__this.call('__init', )
I've implemented this approach in the php-orc project, so feel free to check it out.