Movatterモバイル変換


[0]ホーム

URL:


PHP 8.5.0 Alpha 2 available for testing
    Generator syntax »
    « Generators

    Generators overview

    (PHP 5 >= 5.5.0, PHP 7, PHP 8)

    Generators provide an easy way to implement simpleiterators without the overhead or complexity of implementing a class that implements theIterator interface.

    A generator offers a convenient way to provide data toforeach loops without having to build an array in memory ahead of time, which may cause the program to exceed a memory limit or require a considerable amount of processing time to generate. Instead, a generator function can be used, which is the same as a normalfunction, except that instead ofreturning once, a generator canyield as many times as it needs to in order to provide the values to be iterated over. Like with iterators, random data access is not possible.

    A simple example of this is to reimplement therange() function as a generator. The standardrange() function has to generate an array with every value in it and return it, which can result in large arrays: for example, callingrange(0, 1000000) will result in well over 100 MB of memory being used.

    As an alternative, we can implement anxrange() generator, which will only ever need enough memory to create anIterator object and track the current state of the generator internally, which turns out to be less than 1 kilobyte.

    Example #1 Implementingrange() as a generator

    <?php
    functionxrange($start,$limit,$step=1) {
    if (
    $start<=$limit) {
    if (
    $step<=0) {
    throw new
    LogicException('Step must be positive');
    }

    for (
    $i=$start;$i<=$limit;$i+=$step) {
    yield
    $i;
    }
    } else {
    if (
    $step>=0) {
    throw new
    LogicException('Step must be negative');
    }

    for (
    $i=$start;$i>=$limit;$i+=$step) {
    yield
    $i;
    }
    }
    }

    /*
    * Note that both range() and xrange() result in the same
    * output below.
    */

    echo'Single digit odd numbers from range(): ';
    foreach (
    range(1,9,2) as$number) {
    echo
    "$number ";
    }
    echo
    "\n";

    echo
    'Single digit odd numbers from xrange(): ';
    foreach (
    xrange(1,9,2) as$number) {
    echo
    "$number ";
    }
    ?>

    The above example will output:

    Single digit odd numbers from range():  1 3 5 7 9Single digit odd numbers from xrange(): 1 3 5 7 9

    Generator objects

    When a generator function is called, a new object of the internalGenerator class is returned. This object implements theIterator interface in much the same way as a forward-only iterator object would, and provides methods that can be called to manipulate the state of the generator, including sending values to and returning values from it.

    Found A Problem?

    Learn How To Improve This PageSubmit a Pull RequestReport a Bug
    add a note

    User Contributed Notes6 notes

    181
    bloodjazman at gmail dot com
    11 years ago
    for the protection from the leaking of resources
    see RFChttps://wiki.php.net/rfc/generators#closing_a_generator

    and use finnaly

    sample code

    function getLines($file) {
    $f = fopen($file, 'r');
    try {
    while ($line = fgets($f)) {
    yield $line;
    }
    } finally {
    fclose($f);
    }
    }

    foreach (getLines("file.txt") as $n => $line) {
    if ($n > 5) break;
    echo $line;
    }
    montoriusz at gmail dot com
    9 years ago
    Bear in mind that execution of a generator function is postponed until iteration over its result (the Generator object) begins. This might confuse one if the result of a generator is assigned to a variable instead of immediate iteration.

    <?php

    $some_state
    ='initial';

    function
    gen() {
    global
    $some_state;

    echo
    "gen() execution start\n";
    $some_state="changed";

    yield
    1;
    yield
    2;
    }

    function
    peek_state() {
    global
    $some_state;
    echo
    "\$some_state =$some_state\n";
    }

    echo
    "calling gen()...\n";
    $result=gen();
    echo
    "gen() was called\n";

    peek_state();

    echo
    "iterating...\n";
    foreach (
    $resultas$val) {
    echo
    "iteration:$val\n";
    peek_state();
    }

    ?>

    If you need to perform some action when the function is called and before the result is used, you'll have to wrap your generator in another function.

    <?php
    /**
    * @return Generator
    */
    functionsome_generator() {
    global
    $some_state;

    $some_state="changed";
    return
    gen();
    }
    ?>
    chung1905 at gmail dot com
    5 years ago
    In addition to the note of "montoriusz at gmail dot com":https://www.php.net/manual/en/language.generators.overview.php#119275

    "If you need to perform some action when the function is called and before the result is used, you'll have to wrap your generator in another function."
    You can use Generator::rewind instead (https://www.php.net/manual/en/generator.rewind.php)

    Sample code:
    <?php
    /** function/generator definition **/

    echo"calling gen()...\n";
    $result=gen();
    $result->rewind();
    echo
    "gen() was called\n";

    /** iteration **/
    ?>
    info at boukeversteegh dot nl
    9 years ago
    Here's how to detect loop breaks, and how to handle or cleanup after an interruption.

    <?php
    functiongenerator()
    {
    $complete=false;
    try {

    while ((
    $result=some_function())) {
    yield
    $result;
    }
    $complete=true;

    } finally {
    if (!
    $complete) {
    // cleanup when loop breaks
    } else {
    // cleanup when loop completes
    }
    }

    // Do something only after loop completes
    }
    ?>
    lubaev
    11 years ago
    Abstract test.
    <?php

    $start_time
    =microtime(true);
    $array= array();
    $result='';
    for(
    $count=1000000;$count--;)
    {
    $array[]=$count/2;
    }
    foreach(
    $arrayas$val)
    {
    $val+=145.56;
    $result.=$val;
    }
    $end_time=microtime(true);

    echo
    "time: ",bcsub($end_time,$start_time,4),"\n";
    echo
    "memory (byte): ",memory_get_peak_usage(true),"\n";

    ?>

    <?php

    $start_time
    =microtime(true);
    $result='';
    function
    it()
    {
    for(
    $count=1000000;$count--;)
    {
    yield
    $count/2;
    }
    }
    foreach(
    it() as$val)
    {
    $val+=145.56;
    $result.=$val;
    }
    $end_time=microtime(true);

    echo
    "time: ",bcsub($end_time,$start_time,4),"\n";
    echo
    "memory (byte): ",memory_get_peak_usage(true),"\n";

    ?>
    Result:
    ----------------------------------
    | time | memory, mb |
    ----------------------------------
    | not gen | 2.1216 | 89.25 |
    |---------------------------------
    | with gen | 6.1963 | 8.75 |
    |---------------------------------
    | diff | < 192% | > 90% |
    ----------------------------------
    dc at libertyskull dot com
    11 years ago
    Same example, different results:

    ----------------------------------
    | time | memory, mb |
    ----------------------------------
    | not gen | 0.7589 | 146.75 |
    |---------------------------------
    | with gen | 0.7469 | 8.75 |
    |---------------------------------

    Time in results varying from 6.5 to 7.8 on both examples.
    So no real drawbacks concerning processing speed.
    add a note
    To Top
    and to navigate •Enter to select •Esc to close
    PressEnter without selection to search using Google

    [8]ページ先頭

    ©2009-2025 Movatter.jp