문제

Python(및 기타)에서는 함수에 'yield' 연산자를 사용하여 대량의 데이터를 점진적으로 처리할 수 있습니다.PHP에서 비슷한 방법은 무엇입니까?

예를 들어, Python에서 잠재적으로 매우 큰 파일을 읽고 싶다면 다음과 같이 각 줄을 한 번에 하나씩 작업할 수 있습니다. (이 예는 기본적으로 'for line 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

내가 지금(PHP에서) 하고 있는 일은 상태를 추적하기 위해 전용 인스턴스 변수를 사용하고 함수가 호출될 때마다 그에 따라 작동하는 것인데 더 나은 방법이 있을 것 같습니다.

도움이 되었습니까?

해결책

PHP에는 발전기.

이전 (PHP 5.5 이전 답변):

불행히도 이에 상응하는 언어는 없습니다.가장 쉬운 방법은 이미 수행 중인 작업을 수행하거나 인스턴스 변수를 사용하여 상태를 유지하는 개체를 만드는 것입니다.

그러나 foreach-statement와 함께 함수를 사용하려는 경우 좋은 옵션이 있습니다. SPL 반복자.Python 생성기와 매우 유사한 것을 달성하는 데 사용할 수 있습니다.

다른 팁

RFC가 있습니다. https://wiki.php.net/rfc/generators PHP 5.5에 포함될 수도 있는 바로 그 문제를 해결하는 것입니다.

그동안 사용자 영역에 구현된 가난한 사람의 "생성기 기능"에 대한 개념 증명을 확인하세요.

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

PHP를 포함한 다른 언어로 구현하기 전에 Python으로 모든 것을 프로토타입합니다.나는 결국 콜백을 사용하여 내가 원하는 것을 달성했습니다. 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');

이렇게 각각 $data 콜백 함수에 전달되며 원하는 작업을 수행할 수 있습니다.

@Luiz의 답변 확장 - 또 다른 멋진 방법은 익명 함수를 사용하는 것입니다.

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;

동등한 연산자가 없을 수도 있지만 다음 코드는 기능과 오버헤드 면에서 동일합니다.

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

그 말이 맞는 것 같습니다.죄송합니다. 테스트해 보지 않았습니다.

이제 PHP 5.5에는 'yield'라는 동일한 문장이 존재합니다.

http://php.net/manual/en/언어.generators.syntax.php

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top