수색…
왜 발전기를 사용해야합니까?
생성기는 나중에 반복 할 큰 컬렉션을 생성해야 할 때 유용합니다. 그것들은 자주 반복되는 Iterator 를 구현하는 클래스를 만드는 간단한 대안입니다.
예를 들어 아래 함수를 생각해보십시오.
function randomNumbers(int $length)
{
$array = [];
for ($i = 0; $i < $length; $i++) {
$array[] = mt_rand(1, 10);
}
return $array;
}
이 모든 함수는 임의의 숫자로 채워진 배열을 생성합니다. 그것을 사용하기 위해 우리는 randomNumbers(10)
를 할 것입니다. 그러면 10 개의 난수 배열을 얻을 수 있습니다. 100 만 개의 난수를 생성하려면 어떻게해야합니까? randomNumbers(1000000)
는 우리를 대신하여이를 수행하지만 메모리를 소비합니다. 배열에 저장된 백만 개의 정수는 약 33 메가 바이트 의 메모리를 사용합니다.
$startMemory = memory_get_usage();
$randomNumbers = randomNumbers(1000000);
echo memory_get_usage() - $startMemory, ' bytes';
이것은 한 번에 하나씩이 아니라 총 100 만 개의 난수가 생성되어 즉시 반환되기 때문입니다. 발전기는이 문제를 쉽게 해결할 수있는 방법입니다.
생성자를 사용하여 randomNumbers ()를 다시 작성하십시오.
우리의 randomNumbers()
함수는 생성자를 사용하도록 다시 작성할 수 있습니다.
<?php
function randomNumbers(int $length)
{
for ($i = 0; $i < $length; $i++) {
// yield tells the PHP interpreter that this value
// should be the one used in the current iteration.
yield mt_rand(1, 10);
}
}
foreach (randomNumbers(10) as $number) {
echo "$number\n";
}
생성기를 사용하면 함수에서 반환 할 전체 난수 목록을 작성할 필요가 없으므로 사용되는 메모리가 훨씬 적습니다.
생성기로 큰 파일 읽기
생성자의 일반적인 사용 사례 중 하나는 디스크에서 파일을 읽고 내용을 반복하는 것입니다. 아래는 CSV 파일을 반복 할 수있게 해주는 클래스입니다. 이 스크립트의 메모리 사용량은 매우 예측 가능하며 CSV 파일의 크기에 따라 변동하지 않습니다.
<?php
class CsvReader
{
protected $file;
public function __construct($filePath) {
$this->file = fopen($filePath, 'r');
}
public function rows()
{
while (!feof($this->file)) {
$row = fgetcsv($this->file, 4096);
yield $row;
}
return;
}
}
$csv = new CsvReader('/path/to/huge/csv/file.csv');
foreach ($csv->rows() as $row) {
// Do something with the CSV row.
}
수율 키워드
yield
문은 return 문과 비슷하지만 함수의 실행을 중지하고 반환하는 대신 yield가 Generator 객체를 반환하고 생성기 함수의 실행을 일시 중지합니다.
다음은 생성자로 작성된 범위 함수의 예입니다.
function gen_one_to_three() {
for ($i = 1; $i <= 3; $i++) {
// Note that $i is preserved between yields.
yield $i;
}
}
이 함수는 var_dump
의 출력을 검사하여 Generator 객체를 반환 함을 알 수 있습니다.
var_dump(gen_one_to_three())
# Outputs:
class Generator (0) {
}
수익 가치
Generator 객체는 배열처럼 반복 될 수 있습니다.
foreach (gen_one_to_three() as $value) {
echo "$value\n";
}
위의 예는 다음과 같이 출력됩니다.
1
2
3
키를 사용하여 값 수취하기
값을 산출하는 것 외에도 키 / 값 쌍을 생성 할 수 있습니다.
function gen_one_to_three() {
$keys = ["first", "second", "third"];
for ($i = 1; $i <= 3; $i++) {
// Note that $i is preserved between yields.
yield $keys[$i - 1] => $i;
}
}
foreach (gen_one_to_three() as $key => $value) {
echo "$key: $value\n";
}
위의 예는 다음과 같이 출력됩니다.
first: 1
second: 2
third: 3
send () - 함수를 사용하여 값을 생성기로 전달
생성기는 빠르게 코딩되며 많은 경우 반복기가 많은 구현에 비해 슬림 한 대안입니다. 빠른 구현에서는 발전기가 생성을 멈추거나 다른 것이 생성되어야하는 경우 제어가 약간 부족합니다. 그러나 send()
함수를 사용하여이 작업을 수행 할 수 있습니다. 요청 함수가 매 루프마다 생성기에 매개 변수를 보낼 수 있습니다.
//Imagining accessing a large amount of data from a server, here is the generator for this:
function generateDataFromServerDemo()
{
$indexCurrentRun = 0; //In this example in place of data from the server, I just send feedback everytime a loop ran through.
$timeout = false;
while (!$timeout)
{
$timeout = yield $indexCurrentRun; // Values are passed to caller. The next time the generator is called, it will start at this statement. If send() is used, $timeout will take this value.
$indexCurrentRun++;
}
yield 'X of bytes are missing. </br>';
}
// Start using the generator
$generatorDataFromServer = generateDataFromServerDemo ();
foreach($generatorDataFromServer as $numberOfRuns)
{
if ($numberOfRuns < 10)
{
echo $numberOfRuns . "</br>";
}
else
{
$generatorDataFromServer->send(true); //sending data to the generator
echo $generatorDataFromServer->current(); //accessing the latest element (hinting how many bytes are still missing.
}
}
결과물 :