perezosa - PHP equivalente al operador de rendimiento de Python
programacion funcional pdf (6)
Extendiendo la respuesta de @Luiz - otra manera genial es usar funciones anónimas:
function iterator($n, $cb)
{
for($i=0; $i<$n; $i++) {
call_user_func($cb, $i);
}
}
$sum = 0;
iterator(10,
function($i) use (&$sum)
{
$sum += $i;
}
);
print $sum;
En Python (y otros), puede procesar incrementalmente grandes volúmenes de datos utilizando el operador ''rendimiento'' en una función. ¿Cuál sería la forma similar de hacerlo en PHP?
Por ejemplo, digamos en Python, si quisiera leer un archivo potencialmente muy grande, podría trabajar en cada línea una a la vez como así (este ejemplo está pensado, ya que es básicamente lo mismo que ''for line en file_obj ''):
def file_lines(fname):
f = open(fname)
for line in f:
yield line
f.close()
for line in file_lines(''somefile''):
#process the line
Lo que estoy haciendo ahora (en PHP) es que estoy usando una variable de instancia privada para realizar un seguimiento del estado y actuar en consecuencia cada vez que se llama a la función, pero parece que debe haber una mejor manera.
Hay un rfc en wiki.php.net/rfc/generators dirige a eso, que podría estar incluido en PHP 5.5.
Mientras tanto, echa un vistazo a esta "prueba de concepto" de una "función de generador" de un pobre hombre implementada en la zona de usuario.
namespace Functional;
error_reporting(E_ALL|E_STRICT);
const BEFORE = 1;
const NEXT = 2;
const AFTER = 3;
const FORWARD = 4;
const YIELD = 5;
class Generator implements /Iterator {
private $funcs;
private $args;
private $key;
private $result;
public function __construct(array $funcs, array $args) {
$this->funcs = $funcs;
$this->args = $args;
}
public function rewind() {
$this->key = -1;
$this->result = call_user_func_array($this->funcs[BEFORE],
$this->args);
$this->next();
}
public function valid() {
return $this->result[YIELD] !== false;
}
public function current() {
return $this->result[YIELD];
}
public function key() {
return $this->key;
}
public function next() {
$this->result = call_user_func($this->funcs[NEXT],
$this->result[FORWARD]);
if ($this->result[YIELD] === false) {
call_user_func($this->funcs[AFTER], $this->result[FORWARD]);
}
++$this->key;
}
}
function generator($funcs, $args) {
return new Generator($funcs, $args);
}
/**
* A generator function that lazily yields each line in a file.
*/
function get_lines_from_file($file_name) {
$funcs = array(
BEFORE => function($file_name) { return array(FORWARD => fopen($file_name, ''r'')); },
NEXT => function($fh) { return array(FORWARD => $fh, YIELD => fgets($fh)); },
AFTER => function($fh) { fclose($fh); },
);
return generator($funcs, array($file_name));
}
// Output content of this file with padded linenumbers.
foreach (get_lines_from_file(__FILE__) as $k => $v) {
echo str_pad($k, 8), $v;
}
echo "/n";
La misma frase ''rendimiento'' existe ahora en PHP 5.5:
PHP tiene un equivalente directo llamado se2.php.net/manual/en/language.generators.overview.php .
Antiguo (pre php 5.5 respuesta):
Desafortunadamente, no hay un lenguaje equivalente. La forma más fácil es ya sea a lo que ya está haciendo, o crear un objeto que utiliza variables de instancia para mantener el estado.
Sin embargo, hay una buena opción si desea utilizar la función junto con la instrucción foreach: Iteradores SPL . Se pueden utilizar para lograr algo bastante similar a los generadores de pitón.
Prototipé todo en Python antes de implementarlo en cualquier otro idioma, incluido PHP. Terminé usando devoluciones de llamada para lograr lo que haría con el yield
.
function doSomething($callback)
{
foreach ($something as $someOtherThing) {
// do some computations that generates $data
call_user_func($callback, $data);
}
}
function myCallback($input)
{
// save $input to DB
// log
// send through a webservice
// etc.
var_dump($input);
}
doSomething(''myCallback'');
De esta manera, cada $data
pasa a la función de devolución de llamada y usted puede hacer lo que quiera.
Puede que no haya un operador equivalente, pero el siguiente código es equivalente en función y gastos generales:
function file_lines($file) {
static $fhandle;
if ( is_null($fhandle) ) {
$fhandle = fopen($file, ''r'');
if ( $fhandle === false ) {
return false;
}
}
if ( ($line = fgets($fhandle))!== false ) {
return $line;
}
fclose($fhandle);
$fhandle = null;
}
while ( $line = file_lines(''some_file'') ) {
// ...
}
Eso se ve bien. Lo siento, no lo he probado.