Last active
August 29, 2015 14:26
-
-
Save royopa/5f0935e800b228610052 to your computer and use it in GitHub Desktop.
New translation language/generators.xml - Rodrigo Prado de Jesus <[email protected]>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Index: language/generators.xml | |
=================================================================== | |
--- language/generators.xml (revision 0) | |
+++ language/generators.xml (working copy) | |
@@ -0,0 +1,488 @@ | |
+<?xml version="1.0" encoding="utf-8"?> | |
+<!-- EN-Revision: 330587 Maintainer: royopa Status: ready --><!-- CREDITS: royopa --> | |
+<chapter xml:id="language.generators" xmlns="http://docbook.org/ns/docbook"> | |
+ <title>Generators</title> | |
+ | |
+ <sect1 xml:id="language.generators.overview"> | |
+ <title>Generators - Visão Geral</title> | |
+ <?phpdoc print-version-for="generators"?> | |
+ | |
+ <para> | |
+ Os generators fornecem uma maneira fácil de implementar simples | |
+ <link linkend="language.oop5.iterations">iterators</link> sem a | |
+ sobrecarga ou complexidade de criar uma classe que implemente | |
+ a interface <classname>Iterator</classname>. | |
+ </para> | |
+ | |
+ <para> | |
+ Um generator permite que você escreva código que use &foreach; para iterar | |
+ em um conjunto de dados sem precisar construir um array em memória, o que | |
+ pode fazer com que o limite de memória seja ultrapassado ou exigir uma | |
+ quantidade considerável de tempo de processamento para a geração. Em vez | |
+ disso, você pode escrever uma função generator, que é o mesmo que uma | |
+ <link linkend="functions.user-defined">função</link> normal, exceto que | |
+ ao invés do <link linkend="functions.returning-values">retorno</link> ocorrer | |
+ única vez, um generator pode entregar o resultado quantas vezes forem | |
+ necessárias para permitir que os valores sejam iterados. | |
+ </para> | |
+ | |
+ <para> | |
+ Um exemplo simples para isso é reimplementar a função | |
+ <function>range</function>. A função <function>range</function> padrão | |
+ tem que gerar um array com cada valor dentro dele e retorná-lo, o que pode | |
+ resultar em grandes arrays: por exemplo, chamando | |
+ <command>range(0, 1000000)</command> irá resultar numa utilização de memória | |
+ de mais de 100 MB. | |
+ </para> | |
+ | |
+ <para> | |
+ Como alternativa, nós podemos implementar um generator | |
+ <literal>xrange()</literal>, que só precisará de memória suficiente para | |
+ criar um objeto <classname>Iterator</classname> e acompanhar o estado atual | |
+ do generator internamente, que utiliza menos de 1 kilobyte de memória. | |
+ </para> | |
+ | |
+ <example> | |
+ <title>Implementando <function>range</function> como um generator</title> | |
+ <programlisting role="php"> | |
+<![CDATA[ | |
+<?php | |
+function xrange($start, $limit, $step = 1) { | |
+ if ($start < $limit) { | |
+ if ($step <= 0) { | |
+ throw new LogicException('Step must be +ve'); | |
+ } | |
+ | |
+ for ($i = $start; $i <= $limit; $i += $step) { | |
+ yield $i; | |
+ } | |
+ } else { | |
+ if ($step >= 0) { | |
+ throw new LogicException('Step must be -ve'); | |
+ } | |
+ | |
+ 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 "; | |
+} | |
+?> | |
+]]> | |
+ </programlisting> | |
+ &example.outputs; | |
+ <screen> | |
+<![CDATA[ | |
+Single digit odd numbers from range(): 1 3 5 7 9 | |
+Single digit odd numbers from xrange(): 1 3 5 7 9 | |
+]]> | |
+ </screen> | |
+ </example> | |
+ </sect1> | |
+ | |
+ <sect1 xml:id="language.generators.syntax"> | |
+ <title>Sintaxe do Generator</title> | |
+ | |
+ <para> | |
+ Uma função generator se parece com uma função normal, exceto que ao invés | |
+ de retornar um valor, um generator pode entregar o resultado quantas vezes | |
+ forem necessárias. | |
+ </para> | |
+ | |
+ <para> | |
+ Quando uma função generator é chamada, ela retorna um objeto que pode ser | |
+ iterado. Quando você itera através desse objeto (por exemplo, por um loop | |
+ &foreach;), o PHP irá chamar a função generator toda vez que precisar de | |
+ um valor, em seguida salva o estado do generator quando o valor é produzido, | |
+ de modo que possa ser retomado quando o próximo valor for necessário. | |
+ </para> | |
+ | |
+ <para> | |
+ Uma vez que não há mais valores a serem produzidos, a função generator pode | |
+ simplesmente sair, e a chamada de código continua como se um array tivesse | |
+ executado os valores. | |
+ </para> | |
+ | |
+ <note> | |
+ <para> | |
+ Um generator não pode retornar um valor: isso resultará num erro de | |
+ compilação. Um <command>retorno</command> vazio é uma sintaxe válida e | |
+ fará com que o generator seja encerrado. | |
+ </para> | |
+ </note> | |
+ | |
+ <sect2 xml:id="control-structures.yield"> | |
+ <title>A palavra chave <command>yield</command></title> | |
+ | |
+ <para> | |
+ O coração de uma função generator é a palavra chave | |
+ <command>yield</command>. | |
+ Na sua forma mais simples, uma declaração yield se parece muito com um | |
+ retorno, exceto que em vez de parar a execução da função e retornar, o | |
+ yield fornece um valor para o código de loop sobre o generator e pausa a | |
+ execução da função do generator. | |
+ </para> | |
+ | |
+ <example> | |
+ <title>Um exemplo simples de valores yield</title> | |
+ <programlisting role="php"> | |
+<![CDATA[ | |
+<?php | |
+function gen_one_to_three() { | |
+ for ($i = 1; $i <= 3; $i++) { | |
+ // Note that $i is preserved between yields. | |
+ yield $i; | |
+ } | |
+} | |
+ | |
+$generator = gen_one_to_three(); | |
+foreach ($generator as $value) { | |
+ echo "$value\n"; | |
+} | |
+?> | |
+]]> | |
+ </programlisting> | |
+ &example.outputs; | |
+ <screen> | |
+<![CDATA[ | |
+1 | |
+2 | |
+3 | |
+]]> | |
+ </screen> | |
+ </example> | |
+ | |
+ <note> | |
+ <para> | |
+ Internamente, chaves inteiras sequenciais serão pareadas com os valores | |
+ entregues, assim como um array não associativo. | |
+ </para> | |
+ </note> | |
+ | |
+ <caution> | |
+ <para> | |
+ Se você usar um yield em um contexto da expressão (por exemplo, a direita | |
+ de uma atribuição), você deve colocar a declaração yield entre parênteses. | |
+ Por exemplo, isso é válido: | |
+ </para> | |
+ | |
+ <informalexample> | |
+ <programlisting role="php"> | |
+<![CDATA[ | |
+ $data = (yield $value); | |
+]]> | |
+ </programlisting> | |
+ </informalexample> | |
+ | |
+ <para> | |
+ Mas isso não é válido terá como resultado um parse error: | |
+ </para> | |
+ | |
+ <informalexample> | |
+ <programlisting role="php"> | |
+<![CDATA[ | |
+ $data = yield $value; | |
+]]> | |
+ </programlisting> | |
+ </informalexample> | |
+ | |
+ <para> | |
+ A sintaxe pode ser usada em conjunto com o método | |
+ <methodname>Generator::send</methodname>. | |
+ </para> | |
+ </caution> | |
+ | |
+ <sect3 xml:id="control-structures.yield.associative"> | |
+ <title>Produzindo valores com chaves</title> | |
+ | |
+ <para> | |
+ O PHP suporta arrays associativos e generators não são diferentes. Além | |
+ do produzir valores simples, como mostrado acima, você também pode produzir | |
+ uma chave ao mesmo tempo. | |
+ </para> | |
+ | |
+ <para> | |
+ A sintaxe para preparar um par de chave/valor é muito semelhante ao | |
+ utilizado para definir um array associativo, como mostrado abaixo. | |
+ </para> | |
+ | |
+ <example> | |
+ <title>Produzindo um par de chave/valor</title> | |
+ <programlisting role="php"> | |
+<![CDATA[ | |
+<?php | |
+/* | |
+ * The input is semi-colon separated fields, with the first | |
+ * field being an ID to use as a key. | |
+ */ | |
+ | |
+$input = <<<'EOF' | |
+1;PHP;Likes dollar signs | |
+2;Python;Likes whitespace | |
+3;Ruby;Likes blocks | |
+EOF; | |
+ | |
+function input_parser($input) { | |
+ foreach (explode("\n", $input) as $line) { | |
+ $fields = explode(';', $line); | |
+ $id = array_shift($fields); | |
+ | |
+ yield $id => $fields; | |
+ } | |
+} | |
+ | |
+foreach (input_parser($input) as $id => $fields) { | |
+ echo "$id:\n"; | |
+ echo " $fields[0]\n"; | |
+ echo " $fields[1]\n"; | |
+} | |
+?> | |
+]]> | |
+ </programlisting> | |
+ &example.outputs; | |
+ <screen> | |
+<![CDATA[ | |
+1: | |
+ PHP | |
+ Likes dollar signs | |
+2: | |
+ Python | |
+ Likes whitespace | |
+3: | |
+ Ruby | |
+ Likes blocks | |
+]]> | |
+ </screen> | |
+ </example> | |
+ | |
+ <caution> | |
+ <para> | |
+ Da mesma forma como acontece com o yield de valores simples mostrados | |
+ anteriormente, produzir um par de chave/valor num contexto da expressão | |
+ requer que a declaração do yield esteja entre parênteses: | |
+ </para> | |
+ | |
+ <informalexample> | |
+ <programlisting role="php"> | |
+<![CDATA[ | |
+ $data = (yield $key => $value); | |
+]]> | |
+ </programlisting> | |
+ </informalexample> | |
+ </caution> | |
+ </sect3> | |
+ | |
+ <sect3 xml:id="control-structures.yield.null"> | |
+ <title>Produzindo valores nulos</title> | |
+ | |
+ <para> | |
+ O yield pode ser chamado sem um argumento para produzir um valor &null; | |
+ com uma chave automática. | |
+ </para> | |
+ | |
+ <example> | |
+ <title>Produzindo valores &null;os</title> | |
+ <programlisting role="php"> | |
+<![CDATA[ | |
+<?php | |
+function gen_three_nulls() { | |
+ foreach (range(1, 3) as $i) { | |
+ yield; | |
+ } | |
+} | |
+ | |
+var_dump(iterator_to_array(gen_three_nulls())); | |
+?> | |
+]]> | |
+ </programlisting> | |
+ &example.outputs; | |
+ <screen> | |
+<![CDATA[ | |
+array(3) { | |
+ [0]=> | |
+ NULL | |
+ [1]=> | |
+ NULL | |
+ [2]=> | |
+ NULL | |
+} | |
+]]> | |
+ </screen> | |
+ </example> | |
+ </sect3> | |
+ | |
+ <sect3 xml:id="control-structures.yield.references"> | |
+ <title>Produzindo valores por referência</title> | |
+ | |
+ <para> | |
+ Funções generator são capazes de produzir valores por referência bem como | |
+ por valor. Isso é feito da mesma forma que | |
+ <link linkend="functions.returning-values">retornar referências de funções</link>: | |
+ incluindo um & no início do nome da função. | |
+ </para> | |
+ | |
+ <example> | |
+ <title>Produzindo valores por referência</title> | |
+ <programlisting role="php"> | |
+<![CDATA[ | |
+<?php | |
+function &gen_reference() { | |
+ $value = 3; | |
+ | |
+ while ($value > 0) { | |
+ yield $value; | |
+ } | |
+} | |
+ | |
+/* | |
+ * Note that we can change $number within the loop, and | |
+ * because the generator is yielding references, $value | |
+ * within gen_reference() changes. | |
+ */ | |
+foreach (gen_reference() as &$number) { | |
+ echo (--$number).'... '; | |
+} | |
+?> | |
+]]> | |
+ </programlisting> | |
+ &example.outputs; | |
+ <screen> | |
+<![CDATA[ | |
+2... 1... 0... | |
+]]> | |
+ </screen> | |
+ </example> | |
+ </sect3> | |
+ </sect2> | |
+ | |
+ <sect2 xml:id="language.generators.object"> | |
+ <title>Objetos <classname>Generator</classname></title> | |
+ <para> | |
+ Quando uma função é chamada pela primeira vez, um objeto da classe interna | |
+ <classname>Generator</classname> é retornado. Esse objeto implementa | |
+ a interface <classname>Iterator</classname> da mesma forma como um objeto | |
+ iterator que se move só para frente faria. | |
+ </para> | |
+ </sect2> | |
+ | |
+ </sect1> | |
+ | |
+ <sect1 xml:id="language.generators.comparison"> | |
+ <title>Comparando generators com objetos <classname>Iterator</classname></title> | |
+ | |
+ <para> | |
+ A principal vantagem dos generators é a sua simplicidade. Muito menos código | |
+ clichê tem de ser reescrito em comparação com a implementação de uma classe | |
+ <classname>Iterator</classname>, e o código geralmente é muito mais legível. | |
+ Por exemplo, a seguinte função e classe são equivalentes: | |
+ </para> | |
+ | |
+ <informalexample> | |
+ <programlisting role="php"> | |
+<![CDATA[ | |
+<?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('Couldn\'t open file "' . $fileName . '"'); | |
+ } | |
+ } | |
+ | |
+ public function rewind() { | |
+ fseek($this->fileHandle, 0); | |
+ $this->line = fgets($this->fileHandle); | |
+ $this->i = 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); | |
+ } | |
+} | |
+?> | |
+]]> | |
+ </programlisting> | |
+ </informalexample> | |
+ | |
+ <para> | |
+ No entanto essa flexibilidade tem um custo: os generators somente movem-se | |
+ para frente e não podem ser rebobinados após a iteração ter sido iniciada. | |
+ Isso também significa que o generator não pode ser iterado múltiplas vezes: | |
+ o generator precisará ser reconstruído chamando a função generator novamente, | |
+ ou clonado usando a palavra chave <link linkend="language.oop5.cloning">clone</link>. | |
+ </para> | |
+ </sect1> | |
+</chapter> | |
+ | |
+<!-- Keep this comment at the end of the file | |
+Local variables: | |
+mode: sgml | |
+sgml-omittag:t | |
+sgml-shorttag:t | |
+sgml-minimize-attributes:nil | |
+sgml-always-quote-attributes:t | |
+sgml-indent-step:1 | |
+sgml-indent-data:t | |
+indent-tabs-mode:nil | |
+sgml-parent-document:nil | |
+sgml-default-dtd-file:"~/.phpdoc/manual.ced" | |
+sgml-exposed-tags:nil | |
+sgml-local-catalogs:nil | |
+sgml-local-ecat-files:nil | |
+End: | |
+vim600: syn=xml fen fdm=syntax fdl=2 si | |
+vim: et tw=78 syn=sgml | |
+vi: ts=1 sw=1 | |
+--> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment