Frage

In Python (und andere), können Sie inkrementell große Datenmengen verarbeiten, indem die ‚Ausbeute‘ Operator in einer Funktion. Was wäre die ähnliche Art und Weise sein, so in PHP zu tun?

Zum Beispiel kann in Python sagen, wenn ich eine potenziell sehr große Datei lesen wollte, könnte ich auf jede Linie einer Arbeit in einer Zeit wie so (in diesem Beispiel gekünstelt ist, da es im Grunde das gleiche wie ‚für ist Linie in 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

Was ich jetzt tun (in PHP) ist ich eine private Instanzvariable Spur von Zustand zu halten, und dementsprechend jedes Mal die Funktion aufgerufen wirkende, aber es scheint, als ob es einen besseren Weg.

War es hilfreich?

Lösung

PHP hat eine direkte Entsprechung genannt Generatoren .

Alt (pre PHP 5.5 Antwort):

Leider gibt es keine Sprache gleichwertig. Der einfachste Weg ist es, entweder zu dem, was Sie bereits tun, oder ein Objekt zu erstellen, die Instanzvariablen verwendet Zustand zu halten.

Es gibt jedoch eine gute Option, wenn Sie die Funktion in Verbindung mit der foreach-Anweisung verwenden möchten: SPL Iteratoren . Sie können verwendet werden, um etwas ganz ähnlich wie Python-Generatoren zu erreichen.

Andere Tipps

Es gibt einen rfc unter https://wiki.php.net/rfc/generators nur praxisnah erläutert, dass, die in PHP 5.5 enthalten sein könnten.

In der Zwischenzeit, lesen Sie in diese Proof-of-concept einer armen Mannes "Generatorfunktion" implementiert in Userland.

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";

ich Prototyp alles in Python vor in allen anderen Sprachen der Umsetzung, einschließlich PHP. Ich landete Rückrufe mit zu erreichen, was ich würde mit dem 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');

Auf diese Weise jede $data an die Callback-Funktion übergeben wird, und Sie können tun, was Sie wollen.

Erweiterung @ Luiz Antwort - eine andere coole Art anonyme Funktionen verwenden:

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;

Es kann nicht ein Ersatz Operator sein, aber der folgende Code entspricht in Funktion und Kopf:

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') ) {
  // ...
}

Das sieht ungefähr richtig. Sorry, ich habe es nicht getestet.

Der gleiche Satz 'Ertrag' existiert nun auf PHP 5.5:

http://php.net/manual/en/language.generators. syntax.php

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top