Nota:
Las funciones de este capítulo son para usarlas en el código fuente de PHP y no son funciones de PHP. Se puede encontrar información sobre las funciones de flujos del entorno de usuario en la Referencia de Flujos.
La API de Flujos de PHP introduce una aproximación unificada para el manejo de archivos y sockets de extensiones de PHP. Usando una API única con funciones estándar para operaciones comunes, la API de flujos permite a sus extensiones acceder a archivos, sockets, URLs, memoria y objetos definidos en scripts. Streams (Flujos) es una API extensible en tiempo de ejecución que permite la carga dinámica de módulos (¡y scripts!) para registrar nuevos flujos.
El objetivo de la API de Flujos es hacerla confortable para desarrolladores para abrir ficheros, URLs y otras fuentes de datos que se pueden utilizar como flujos con una API unificada que es fácil de entender. La API está más o menos basada en la familia de funciones stdio de ANSI C (con semántica idéntica para la mayoría de las funciones principales), por lo que los programadores de C estarán familiarizados con los flujos.
La API de flujos opera en dos niveles diferentes: en el nivel básico, la API define objetos php_stream para representar fuentes de datos que se pueden usar como flujos. En un nivel ligeramente superior, la API define objetos php_stream_wrapper que "envuelven" al nivel inferior de la API para proporcionar soporte para recuperar información y meta-información desde URLs. Un parámetro adicional, context, aceptado por la mayoría de las funciones de creación de flujos, es pasado al método stream_opener de la envoltura para mejorar el comportamiento de la envoltura.
Un flujo, una vez abierto, también puede tener cualquier número de filtros aplicados a él, que procesan la información que es leída desde/escrita en el flujo.
Los flujos pueden ser convertidos (cast) en otros tipos de gestores de archivos, por lo que se pueden usar con bibliotecas de terceros sin grandes dificultades. Esto permite a estas bibliotecas acceder a la información directamente desde fuentes de URL. Si su sistema tiene la función fopencookie() o funopen(), ¡puede incluso pasar cualquier flujo de PHP a cualquier biblioteca de use stdio de ANSI!
Usar flujos es muy parecido a usar las funciones de stdio de ANSI. La principal diferencia está en la manera en de obtiener el gestor de flujo para empezar con él. En la mayoría de los casos se usará php_stream_open_wrapper() para obtener el gestor de flujo. Esta función trabaja de manera similar a fopen, como se puede ver en el ejemplo de abajo:
Ejemplo #1 ejemplo sencillo de flujo que muestra la página de inicio de PHP
php_stream * stream = php_stream_open_wrapper("http://www.php.net", "rb", REPORT_ERRORS, NULL); if (stream) { while(!php_stream_eof(stream)) { char buf[1024]; if (php_stream_gets(stream, buf, sizeof(buf))) { printf(buf); } else { break; } } php_stream_close(stream); }
La tabla de abajo muestra la equivalencia entre Flujos y las funciones stdio de ANSI más comunes. A menos que se anote lo contrario, la semántica de las funciones son idénticas.
Función Stdio de ANSI | Función de Flujos de PHP | Notas |
---|---|---|
fopen | php_stream_open_wrapper | Los Flujos incluyen parámetros adicionales |
fclose | php_stream_close | |
fgets | php_stream_gets | |
fread | php_stream_read | El parámetro nmemb se asume que tiene un valor de 1, por lo que el prototipo se parece más a read(2) |
fwrite | php_stream_write | El parámetro nmemb se asume que tiene un valor de 1, por lo que el prototipo se parece más a write(2) |
fseek | php_stream_seek | |
ftell | php_stream_tell | |
rewind | php_stream_rewind | |
feof | php_stream_eof | |
fgetc | php_stream_getc | |
fputc | php_stream_putc | |
fflush | php_stream_flush | |
puts | php_stream_puts | La misma semántica que puts, NO fputs |
fstat | php_stream_stat | Los flujos tienen una estructura de estadísticas más abundante |
Todos los flujos están registrados como recursos cuando son creados. Esto asegura que serán limpiados de manera apropiada incluso si hubiera un error fatal. Todas las funciones de sistema de archivos de PHP operan sobre recursos de flujos - esto significa que sus extensiones pueden aceptar punteros a archivos de PHP habituales como parámetros, y devovler flujos desde sus funciones. La API de flujos realiza este proceso de la forma más sencilla posible:
Ejemplo #2 Cómo aceptar un flujo como parámetro
PHP_FUNCTION(example_write_hello) { zval *zstream; php_stream *stream; if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &zstream)) return; php_stream_from_zval(stream, &zstream); /* ahora se puede usar el flujo. Sin embargo, usted no es el "propietario" del flujo; lo es el script. Esto significa que NO DEBE cerrar el flujo, ¡ya que causaría que PHP se colgara! */ php_stream_write(stream, "hello\n"); RETURN_TRUE(); }
Ejemplo #3 Cómo devolver un flujo desde una función
PHP_FUNCTION(example_open_php_home_page) { php_stream *stream; stream = php_stream_open_wrapper("http://www.php.net", "rb", REPORT_ERRORS, NULL); php_stream_to_zval(stream, return_value); /* después de este punto, el flujo es "propiedad" del script. ¡Si lo cierra ahora PHP se colgará! */ }
Ya que los flujos se limpian automáticamente, es tentador pensar que podemos zafarnos y ser unos programadores descuidados y no molestarnos en cerrar los flujos cuando hayamos terminado con ellos. Aunque tal enfoque podría funcionar, no es una buena idea por varias razones: los flujos permanecen bloqueados en los recursos del sistema mientras están abiertos, por lo que dejar un archivo abierto después de que se haya terminado con él podría impedir que otros procesos accedan al mismo. Si un script trata con un gran número de archivos, la acumulación de recursos usados, tanto en términos de memoria como en el número de archivos abiertos, puede causar que las peticiones al servidor web fallen. Suena mal, ¿verdad? La API de flujos incluye algo de magia que le puede ayudar a mantener su código limpio - si un flujo es cerrado por su código cuando debería hacerlo, puede encontrar alguna información de depuración útil en el registro de errores de su servidor web.
Nota: Use siempre uan construcción de depuración de PHP al desarrollar una extensión (--enable-debug cuando se ejecute configure), ya que se ha realizado un mucho esfuerzo para advertirle de filtraciones de memoria y flujos.
En algunos casos es útil mantener un flujo abierto durante una petición, para actuar como un archivo de registro o de seguimiento, por ejemplo. Escribir código para limpiar de forma segura un flujo no es difícil, pero requiere varias líneas de código que no son estrictamente necesarias. Para ahorrarse el problema de escribir el código puede marcar un flujo como OK para su autolimpieza. Esto significa que la API de flujos no emitirá una advertencia cuando es hora de autolimpiar un flujo. Para hacer esto puede usar php_stream_auto_cleanup().
Estas constantes afectan a la operación de funciones de flujos de fábrica.
IGNORE_PATH
USE_PATH
IGNORE_URL
IGNORE_URL_WIN
ENFORCE_SAFE_MODE
REPORT_ERRORS
STREAM_MUST_SEEK
Nota: Si el recurso solicitado está basado en una red, esta bandera causará que el abridor bloquee hasta que el contenido completo haya sido descargado.
STREAM_WILL_CAST