texto tag strip_tags remove name limpiar etiquetas ejemplo php generator php-5.5 yield-keyword

php - remove - strip_tags wordpress



¿Qué significa el rendimiento en PHP? (5)

Recientemente me encontré con este código:

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

Nunca antes había visto esta palabra clave yield . Estoy tratando de ejecutar el código que obtengo

Error de análisis: error de sintaxis, inesperado T_VARIABLE en la línea x

Entonces, ¿qué es esta palabra clave de yield ? ¿Es incluso válido PHP? Y si lo es, ¿cómo lo uso?


¿Qué es el yield ?

La palabra clave yield devuelve datos de una función del generador:

El corazón de una función de generador es la palabra clave yield. En su forma más simple, un enunciado de rendimiento se parece mucho a una declaración de retorno, excepto que en lugar de detener la ejecución de la función y devolver, el rendimiento proporciona un valor al código que gira sobre el generador y detiene la ejecución de la función del generador.

¿Qué es una función de generador?

Una función de generador es efectivamente una forma más compacta y eficiente de escribir un Iterator . Le permite definir una función (su xrange ) que calculará y devolverá los valores mientras lo hace un bucle :

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

Esto crearía el siguiente resultado:

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

También puede controlar la $key en el foreach usando

yield $someKey => $someValue;

En la función del generador, $someKey es lo que quieras que aparezca para $key y $someValue como el valor en $val . En el ejemplo de la pregunta, eso es $i .

¿Cuál es la diferencia para las funciones normales?

Ahora podría preguntarse por qué no estamos utilizando simplemente la función de range nativo de PHP para lograr esa salida. Y correcto eres. La salida sería la misma. La diferencia es cómo llegamos allí.

Cuando usamos el range PHP, lo ejecutaremos, crearemos toda la matriz de números en la memoria y return esa matriz completa al bucle foreach que luego pasará sobre ella y emitirá los valores. En otras palabras, el foreach operará en la matriz misma. La función de range y el foreach solo "hablan" una vez. Piense que es como recibir un paquete por correo. El repartidor le entregará el paquete y se irá. Y luego desenvuelves todo el paquete, sacando lo que está allí.

Cuando usamos la función del generador, PHP entrará en la función y la ejecutará hasta que se encuentre con el final o una palabra clave yield . Cuando se encuentre con un yield , devolverá el valor que sea en ese momento al bucle externo. Luego regresa a la función del generador y continúa desde donde cedió. Como su xrange contiene un ciclo for , se ejecutará y cederá hasta que se alcance $max . Piense en ello como el foreach y el generador jugando ping pong.

¿Por qué lo necesito?

Obviamente, los generadores se pueden usar para evitar los límites de memoria. Dependiendo de su entorno, hacer un range(1, 1000000) será fatal para su script, mientras que lo mismo con un generador funcionará bien. O como dice Wikipedia:

Debido a que los generadores computan sus valores arrojados solo a pedido, son útiles para representar secuencias que serían costosas o imposibles de calcular de una vez. Estos incluyen, por ejemplo, secuencias infinitas y flujos de datos en vivo.

Se supone que los generadores también son bastante rápidos. Pero tenga en cuenta que cuando estamos hablando de rápido, generalmente estamos hablando en números muy pequeños. Entonces, antes de salir corriendo y cambiar todo su código para usar generadores, haga un punto de referencia para ver dónde tiene sentido.

Otro caso de uso para generadores es correcciones asincrónicas. La palabra clave yield no solo devuelve valores sino que también los acepta. Para detalles sobre esto, vea las dos excelentes publicaciones de blog vinculadas a continuación.

¿Desde cuándo puedo usar el yield ?

Los generadores se han introducido en PHP 5.5 . Intentar usar el yield antes de esa versión dará como resultado varios errores de análisis, dependiendo del código que sigue a la palabra clave. Entonces, si obtiene un error de análisis de ese código, actualice su PHP.

Fuentes y lecturas adicionales:


Con yield , puede describir fácilmente los puntos de corte entre múltiples tareas en una sola función. Eso es todo, no hay nada especial al respecto.

$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, ...);

Si task1 y task2 están altamente relacionados, pero necesita un punto de interrupción entre ellos para hacer algo más:

  • memoria libre entre las filas de la base de datos de procesamiento
  • ejecutar otras tareas que proporcionan dependencia a la siguiente tarea, pero que no están relacionadas al entender el código actual
  • haciendo llamadas asíncronas y esperando los resultados
  • y así ...

luego los generadores son la mejor solución, porque no tiene que dividir el código en muchos cierres ni mezclarlo con otro código, ni usar devoluciones de llamadas, etc. Simplemente usa el yield para agregar un punto de interrupción, y puede continuar desde ese punto de quiebre si estás listo.

Agregar punto de interrupción sin generadores:

$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); //...

Agregar punto de interrupción con generadores

$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);

nota: Es fácil cometer errores con los generadores, por lo tanto, siempre escriba las pruebas unitarias antes de implementarlas. nota 2: Usar generadores en un bucle infinito es como escribir un cierre que tiene una longitud infinita ...


Esta función usando rendimiento:

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

es casi lo mismo que este sin:

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

Con solo una diferencia, a() devuelve un generator y b() solo una matriz simple. Sin embargo, puede iterar en ambos, que es el aspecto importante.


yield palabra clave yield sirve para la definición de "generadores" en PHP 5.5. Bien, entonces, ¿qué es un generator ?

Desde php.net:

Los generadores proporcionan una manera fácil de implementar iteradores simples sin la sobrecarga o la complejidad de implementar una clase que implemente la interfaz Iterator.

Un generador le permite escribir código que utiliza foreach para iterar sobre un conjunto de datos sin necesidad de construir una matriz en la memoria, lo que puede causar que exceda un límite de memoria, o requiera una cantidad considerable de tiempo de procesamiento para generar. En su lugar, puede escribir una función de generador, que es lo mismo que una función normal, excepto que en lugar de volver una vez, un generador puede ceder tantas veces como sea necesario para proporcionar los valores que se van a repetir.

Desde este lugar: generadores = generadores, otras funciones (solo funciones simples) = funciones.

Entonces, son útiles cuando:

  • necesitas hacer cosas simples (o simples);

    generador es realmente mucho más simple que implementar la interfaz Iterator. Por otra parte, es de origen que los generadores son menos funcionales. generator .

  • necesita generar GRANDES cantidades de datos, guardar la memoria;

    En realidad, para ahorrar memoria, podemos simplemente generar los datos necesarios a través de funciones para cada iteración de bucle, y después de la iteración utilizar la basura. así que aquí los puntos principales son: código claro y probablemente rendimiento. vea qué es mejor para sus necesidades.

  • necesitas generar secuencia, que depende de valores intermedios;

    esto se extiende al pensamiento anterior. los generadores pueden facilitar las cosas en comparación con las funciones. verifique el ejemplo de Fibonacci y trate de hacer una secuencia sin generador. También los generadores pueden trabajar más rápido en este caso, al menos porque almacenan valores intermedios en variables locales;

  • necesitas mejorar el rendimiento

    pueden funcionar más rápido que las funciones en algunos casos (ver beneficio anterior);


ejemplo simple

<?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#''; ?>

salida

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