PHP Australia Conference 2015

Comparaison des générateurs avec les objets Iterator

Le principal avantage des générateurs est leur simplicité. Moins de code doit être écrit que lorsqu'il s'agit d'implémenter une classe Iterator, et il est généralement plus lisible. Par exemple, la fonction et la classe suivante sont équivalentes :

<?php
function getLinesFromFile($fileName) {
    if (!
$fileHandle fopen($fileName'r')) {
        return;
    }
 
    while (
false !== $line fgets($fileHandle)) {
        yield 
$line;
    }
 
    
fclose($fileHandle);
}

// versus...

class LineIterator implements Iterator {
    protected 
$fileHandle;
 
    protected 
$line;
    protected 
$i;
 
    public function 
__construct($fileName) {
        if (!
$this->fileHandle fopen($fileName'r')) {
            throw new 
RuntimeException('Impossible d\'ouvrir le fichier : "' $fileName '"');
        }
    }
 
    public function 
rewind() {
        
fseek($this->fileHandle0);
        
$this->line fgets($this->fileHandle);
        
$this->0;
    }
 
    public function 
valid() {
        return 
false !== $this->line;
    }
 
    public function 
current() {
        return 
$this->line;
    }
 
    public function 
key() {
        return 
$this->i;
    }
 
    public function 
next() {
        if (
false !== $this->line) {
            
$this->line fgets($this->fileHandle);
            
$this->i++;
        }
    }
 
    public function 
__destruct() {
        
fclose($this->fileHandle);
    }
}
?>

Cependant, cette flexibilité a un coût : les générateurs sont des itérateurs n'allant que vers l'avant, et ils ne peuvent pas être ré-initialisés une fois leur parcours commencé. Cela signifie également que le même générateur ne peut pas être utilisé à plusieurs reprises : le générateur devra être soit reconstruit en appelant une nouvelle fois la fonction générateur, soit clôné via le mot clé clone.

add a note add a note

User Contributed Notes 3 notes

up
13
mNOSPAMsenghaa at nospam dot gmail dot com
1 year ago
This hardly seems a fair comparison between the two examples, size-for-size. As noted, generators are forward-only, meaning that it should be compared to an iterator with a dummy rewind function defined. Also, to be fair, since the iterator throws an exception, shouldn't the generator example also throw the same exception? The code comparison would become more like this:

<?php
function getLinesFromFile($fileName) {
    if (!
$fileHandle = fopen($fileName, 'r')) {
        throw new
RuntimeException('Couldn\'t open file "' . $fileName . '"');
    }

    while (
false !== $line = fgets($fileHandle)) {
        yield
$line;
    }

   
fclose($fileHandle);
}

// versus...

class LineIterator implements Iterator {
    protected
$fileHandle;

    protected
$line;
    protected
$i;

    public function
__construct($fileName) {
        if (!
$this->fileHandle = fopen($fileName, 'r')) {
            throw new
RuntimeException('Couldn\'t open file "' . $fileName . '"');
        }
    }

    public function
rewind() { }

    public function
valid() {
        return
false !== $this->line;
    }

    public function
current() {
        return
$this->line;
    }

    public function
key() {
        return
$this->i;
    }

    public function
next() {
        if (
false !== $this->line) {
           
$this->line = fgets($this->fileHandle);
           
$this->i++;
        }
    }

    public function
__destruct() {
       
fclose($this->fileHandle);
    }
}
?>

The generator is still obviously much shorter, but this seems a more reasonable comparison.
up
0
sergeyzsg at yandex dot ru
3 months ago
I think that this is bad generator example.
If user will not consume all lines then file will not be closed.

<?php
function getLinesFromFile($fileHandle) {
    while (
false !== $line = fgets($fileHandle)) {
        yield
$line;
    }
}

if (
$fileHandle = fopen($fileName, 'r')) {
   
/*
    something with getLinesFromFile
    */
   
fclose($fileHandle);
}
?>
up
0
sou at oand dot re
1 year ago
I think to be more similar the samples in the function, throw a new exception is better. But looking into "Generator syntax" session, you can see there this: "An empty return statement is valid syntax within a generator and it will terminate the generator.". By this point of view, we can imagine that this is just to exemplify an usage of the empty return.
To Top