Programing

PHP에서 yield는 무엇을 의미합니까?

lottogame 2020. 4. 30. 07:25
반응형

PHP에서 yield는 무엇을 의미합니까?


최근 에이 코드를 우연히 발견했습니다.

function xrange($min, $max) 
{
    for ($i = $min; $i <= $max; $i++) {
        yield $i;
    }
}

yield키워드를 본 적이 없습니다 . 내가 얻은 코드를 실행하려고합니다.

구문 분석 오류 : 구문 오류, x 행의 예기치 않은 T_VARIABLE

yield키워드 는 무엇 입니까? 유효한 PHP입니까? 그리고 그렇다면 어떻게 사용합니까?


무엇입니까 yield?

yield키워드 발전기 기능에서 데이터를 반환합니다 :

생성기 함수의 핵심은 yield 키워드입니다. 가장 간단한 형식으로, yield 문은 함수의 실행을 중지하고 반환하는 대신 yield가 대신 생성자를 반복하는 코드에 값을 제공하고 생성기 함수의 실행을 일시 중지한다는 점을 제외하면 return 문과 매우 유사합니다.

발전기 기능이란 무엇입니까?

제너레이터 함수는 효과적으로 Iterator 를 작성하는보다 간결하고 효율적인 방법 입니다. 그것은 당신이 함수 (사용자 정의 할 수 있습니다 xrange것) 계산하고 반환동안 당신이 그것을 통해 루프를 :

foreach (xrange(1, 10) as $key => $value) {
    echo "$key => $value", PHP_EOL;
}

다음과 같은 출력이 생성됩니다.

0 => 1
1 => 2
9 => 10

또한 제어 할 수 있습니다 $key에서를 foreach사용하여

yield $someKey => $someValue;

발전기 기능에, $someKey당신이 나타납니다 원하는대로입니다 $key$someValue의 가치 $val. 질문의 예에서는 $i입니다.

일반 기능과의 차이점은 무엇입니까?

이제 왜 우리가 단순히 그 출력을 달성하기 위해 PHP의 원시 range함수사용하지 않는지 궁금 할 것 입니다. 그리고 바로 당신입니다. 출력은 동일합니다. 차이점은 우리가 어떻게 도착했는지입니다.

우리가 rangePHP 를 사용할 때 , 그것을 실행하고, 메모리 return전체 숫자 배열을 만들고 전체 배열foreach루프로 만든 다음 그 값으로 넘어갑니다. 즉, foreach배열 자체에서 작동합니다. range기능과 foreach한 번만 "대화". 우편물에 패키지를 넣는 것처럼 생각하십시오. 배달원이 패키지를 건네고 떠납니다. 그런 다음 전체 패키지를 풀고 거기에있는 것을 꺼내십시오.

생성기 함수를 사용할 때 PHP는 함수로 들어가서 끝이나 yield키워드에 도달 할 때까지 실행합니다 . a를 만나면 yield그 당시의 값이 무엇이든 외부 루프로 반환합니다. 그런 다음 생성기 기능으로 돌아가서 생성 된 위치부터 계속됩니다. 루프를 xrange보유하고 있기 때문에 for루프가 실행되고 $max도달 할 때까지 생성 됩니다. foreach탁구 를 만드는 발전기와 같은 것을 생각해보십시오 .

왜 그런가요?

분명히, 생성기를 사용하여 메모리 제한을 해결할 수 있습니다. 환경에 따라 range(1, 1000000)유언장을 작성하면 스크립트가 치명적이지만 생성기와 동일하게 작동합니다. 또는 Wikipedia는 다음과 같이 말합니다.

Because generators compute their yielded values only on demand, they are useful for representing sequences that would be expensive or impossible to compute at once. These include e.g. infinite sequences and live data streams.

Generators are also supposed to be pretty fast. But keep in mind that when we are talking about fast, we are usually talking in very small numbers. So before you now run off and change all your code to use generators, do a benchmark to see where it makes sense.

Another Use Case for Generators is asynchronous coroutines. The yield keyword does not only return values but it also accepts them. For details on this, see the two excellent blog posts linked below.

Since when can I use yield?

Generators have been introduced in PHP 5.5. Trying to use yield before that version will result in various parse errors, depending on the code that follows the keyword. So if you get a parse error from that code, update your PHP.

Sources and further reading:


This function using yield:

function a($items) {
    foreach ($items as $item) {
        yield $item + 1;
    }
}

is almost the same as this one without:

function b($items) {
    $result = [];
    foreach ($items as $item) {
        $result[] = $item + 1;
    }
    return $result;
}

With only one difference that a() returns a generator and b() just a simple array. You can iterate on both.

Also, the first one does not allocate a full array and is therefore less memory-demanding.


yield keyword serves for definition of "generators" in PHP 5.5. Ok, then what is a generator?

From php.net:

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

A generator allows you to write code that uses foreach to iterate over a set of data without needing to build an array in memory, which may cause you to exceed a memory limit, or require a considerable amount of processing time to generate. Instead, you can write a generator function, which is the same as a normal function, except that instead of returning once, a generator can yield as many times as it needs to in order to provide the values to be iterated over.

From this place: generators = generators, other functions (just a simple functions) = functions.

So, they are useful when:

  • you need to do things simple (or simple things);

    generator is really much simplier then implementing the Iterator interface. other hand is, ofcource, that generators are less functional. compare them.

  • you need to generate BIG amounts of data - saving memory;

    actually to save memory we can just generate needed data via functions for every loop iteration, and after iteration utilize garbage. so here main points is - clear code and probably performance. see what is better for your needs.

  • you need to generate sequence, which depends on intermediate values;

    this is extending of the previous thought. generators can make things easier in comparison with functions. check Fibonacci example, and try to make sequence without generator. Also generators can work faster is this case, at least because of storing intermediate values in local variables;

  • you need to improve performance.

    they can work faster then functions in some cases (see previous benefit);


simple example

<?php
echo '#start main# ';
function a(){
    echo '{start[';
    for($i=1; $i<=9; $i++)
        yield $i;
    echo ']end} ';
}
foreach(a() as $v)
    echo $v.',';
echo '#end main#';
?>

output

#start main# {start[1,2,3,4,5,6,7,8,9,]end} #end main#

With yield you can easily describe the breakpoints between multiple tasks in a single function. That's all, there is nothing special about it.

$closure = function ($injected1, $injected2, ...){
    $returned = array();
    //task1 on $injected1
    $returned[] = $returned1;
//I need a breakpoint here!!!!!!!!!!!!!!!!!!!!!!!!!
    //task2 on $injected2
    $returned[] = $returned2;
    //...
    return $returned;
};
$returned = $closure($injected1, $injected2, ...);

If task1 and task2 are highly related, but you need a breakpoint between them to do something else:

  • free memory between processing database rows
  • run other tasks which provide dependency to the next task, but which are unrelated by understanding the current code
  • doing async calls and wait for the results
  • and so on ...

then generators are the best solution, because you don't have to split up your code into many closures or mix it with other code, or use callbacks, etc... You just use yield to add a breakpoint, and you can continue from that breakpoint if you are ready.

Add breakpoint without generators:

$closure1 = function ($injected1){
    //task1 on $injected1
    return $returned1;
};
$closure2 = function ($injected2){
    //task2 on $injected2
    return $returned1;
};
//...
$returned1 = $closure1($injected1);
//breakpoint between task1 and task2
$returned2 = $closure2($injected2);
//...

Add breakpoint with generators

$closure = function (){
    $injected1 = yield;
    //task1 on $injected1
    $injected2 = (yield($returned1));
    //task2 on $injected2
    $injected3 = (yield($returned2));
    //...
    yield($returnedN);
};
$generator = $closure();
$returned1 = $generator->send($injected1);
//breakpoint between task1 and task2
$returned2 = $generator->send($injected2);
//...
$returnedN = $generator->send($injectedN);

note: It is easy to make mistake with generators, so always write unit tests before you implement them! note2: Using generators in an infinite loop is like writing a closure which has infinite length...


An interesting aspect, which worth to be discussed here, is yielding by reference. Every time we need to change a parameter such that it is reflected outside of the function, we have to pass this parameter by reference. To apply this to generators, we simply prepend an ampersand & to the name of the generator and to the variable used in the iteration:

 <?php 
 /**
 * Yields by reference.
 * @param int $from
 */
function &counter($from) {
    while ($from > 0) {
        yield $from;
    }
}

foreach (counter(100) as &$value) {
    $value--;
    echo $value . '...';
}

// Output: 99...98...97...96...95...

The above example shows how changing the iterated values within the foreach loop changes the $from variable within the generator. This is because $from is yielded by reference due to the ampersand before the generator name. Because of that, the $value variable within the foreach loop is a reference to the $from variable within the generator function.

참고 URL : https://stackoverflow.com/questions/17483806/what-does-yield-mean-in-php

반응형