PSRs: estándares en PHP

El objetivo de este artículo no es hacer una revisión técnica detallada de cada estándar definido en los PSRs. Para eso ya tenemos la definición de cada uno de ellos en si misma.

El objetivo es, por tanto, hacer un repaso a más alto nivel de cada estándar de una forma más o menos sencilla para conocerlos y saber que definen y que nos ofrecen.

¿Qué son los PSRs?

PSRs (PHP Standards Recommendations) define un conjunto de estándares que facilitan el desarrollo de aplicaciones y la interoperabilidad entre proyectos.

¿Quién define los PSRs?

Los estándares de PHP están definidos por el PHP -FIG (PHP-Framework Interop Group), un grupo que nació en la conferencia php|tek de 2009.

PHP-FIG tiene como objetivos promover el ecosistema de PHP y definir estándares basados en la investigación, experimentación y sobre todo en la experiencia del mundo real, para facilitar la colaboración entre programadores y proyectos.

Los miembros de PHP-FIG son personas, proyectos y organizaciones conocidos y reconocidos en el mundo PHP. Las organizaciones que pertenecen al grupo, han demostrado un interés real en apoyar la misión, los objetivos y el trabajo del FIG. Los proyectos pertenecientes deben estar liberados con implementaciones reales conocidas.

El grupo no es fijo y cerrado, sino que está abierto a nuevas incorporaciones y salidas de los que ya están dentro de forma que un proyecto miembro puede renunciar a pertenecer al PHP-FIG cuando lo estime oportuno y puede volver a solicitar su incorporación cuando lo desee. Como frameworks más relevantes que ya no están en el grupo tenemos a Doctrine, Guzzle, Laravel o Symfony.

¿Cómo se crea un estándar PSR en el PHP-FIG?

Cada vez que se propone un estándar por algún grupo de trabajoeste debe ser votado. Una vez haya pasado la votación de ingreso aparecerá como ‘draft’, lo que significa que ya se está trabajando en él y aún puede estar sujeto a modificaciones de cualquier tipo. Una vez haya pasado al estado ‘accepted’, si hay cambios, estos serán menores.

Los estados en los que puede estar un estándar son los siguientes:

  • Pre-draft: El objetivo es determinar si una mayoría del PHP-FIG está interesada en una propuesta del PSR para el concepto propuesto. Si es aceptada, la propuesta recibe un número incremental e identificativo y pasa al siguiente estado.
  • Draft: El objetivo es discutir y darle forma a una propuesta del PSRs hasta que pueda ser considerada para su revisión por el comité central del grupo. En esta fase, los miembros que trabajen en ella pueden hacer los cambios que consideren necesarios vía pull request.
  • Review: El objetivo es que la comunidad pueda experimentar para evaluar la practicidad de la propuesta. Los únicos cambios permitidos son limitados y se consideran menores. A menos que vuelva a draft, un estándar en esta fase de review debe permanecer al menos cuatro semanas y hasta que se puedan demostrar dos implementaciones de pruebas independientes. Una vez cumplidas estas dos condiciones, se puede volver a votar para ver si pasa a la siguiente fase.
  • Accepted: En este punto, la propuesta se vuelve oficialmente un estándar PSR.
  • Deprecated: Un estándar que está en esta fase es un estándar que ha sido aprobado pero que ya no se considera relevante o recomendado. Normalmente suele pasar porque ha sido reemplazado por una nueva versión.
  • Abandoned: Un estándar abandonado es aquel en el que no se está trabajando activamente. Esto se produce cuando no tenga la figura de un editor o patrocinador al menos durante 60 días o también cuando no se produzca durante al menos seis meses una actividad relevante en el grupo de trabajo que tenga asignado. Una propuesta abandonada, solo puede volver a ser considerada por el FIG pasando nuevamente por el proceso natural de cualquier propuesta nueva, es decir, votándola para comenzar desde draft.
  • Projet referéndum: En cualquier momento, un editor de un PSR en draft o en review, puede solicitar un referéndum sobre el estado actual de un PSR. Dicho referéndum puede convocarse tantas veces como se considere necesario. Aunque el resultado no es vinculante, se espera que tanto el grupo de trabajo del estándar afectado como el comité central del grupo presten la debida consideración a los resultados.

Listado de estándares PSR

PSR-0 Autoloading Standard (Status: Deprecated)

Fue marcado como deprecated (obsoleto) el 21–10–2014 en favlor de PSR-4. El estándar PSR-0 describe los requisitos obligatorios (prácticas y restricciones), que deben ser satisfechos para la interoperabilidad del autocargador, es decir, para la carga automática de clases.

Cuando programamos, lo más normal es tener una clase por archivo. Antes de utilizar una clase PHP debe conocerla, es decir, debemos indicarle a PHP en que archivo se encuentra. Si el proyecto es pequeño y tiene pocas dependencias, casi que nosotros de manera manual podemos decirle a PHP donde se encuentra cada clase pero, si el proyecto es grande y tiene muchas dependencias, puede ser realmente complicado.

Después de la introducción de los namespaces en PHP 5.3, fue cuando se propuso este estándar para que en base a ciertas características definidas de cada namespace de cada clase, se pudiera “autodescubrir” de forma automática cuando necesitáramos una instancia de dicha clase.

Es decir, PSR-0 viene a decirnos como definir los namespaces de cada clase para que PHP pueda hacer la “magia” necesaria para encontrarlas.

PSR-1: Basic Coding Standard (Status: Accepted)

Este estándar comprende como debería ser la codificación de los elementos necesarios para asegurar la interoperabilidad de código compartido. Es decir, indican normas de codificación básica a muy bajo nivel como por ejemplo la codificación de caracteres en UTF-8 o el tipo de escritura que deben seguir los nombres de las clases (StudlyCaps) o métodos (camelCase).

PSR-2: Coding Style Guide (Status: Accepted)

Este estándar extiende a PSR-1. La finalidad de PSR-2 es reducir la carga cognitiva que supone leer y entender código de diferentes desarrolladores.

Para ello, enumera unas normas de estilo básicas que consiguen hacer que el código de un proyecto sea más simétrico y predecible. En PHP, PSR-2 suponen las normas más básicas de codificación que un equipo de desarrollo debiera tener en cuenta a la hora de programar.

PSR-3: Looger Interface (Status: Accepted)

Entendemos por ‘log’ al registro o grabación secuencial en un sistema de persistencia eventos que ocurren en nuestro sistema, de manera que posteriormente puedan ser procesados y obtener así las evidencias que sean oportunas.

PSR-3 define un interface común para librerías de loggin de manera que pueda utilizarse esta funcionalidad en cualquier aplicación de forma sencilla. Cada librería de log, posteriormente, puede estar implementada como mejor considere, pero, para asegurarse que cualquier aplicación pueda usarla sin problemas debe cumplir PSR-3.

La definición de Logger Interface expone ocho métodos (debug, info, notice, warning, error, critical, alert, emergency), correspondientes a los ocho niveles de log definidos en el RF 5424.

Es decir, si queremos implementar una librería de log que sea compatible con otras aplicaciones, debe cumplir con PSR-3. Y si usamos una librería de loggin que cumpla PSR-3 sabemos que debe funcionar.

Ejemplo de Logger Inteface.

PSR-4: PSR-4: Autoloader (Status: Accepted)

Muy relacionada con PSR-0. En este caso, PSR-4 describe también una especificación sobre como tiene que ser la autocarga de clases.

Es compatible con PSR-0, aunque con otras características que lo mejoran. Entre sus diferencias más notables tenemos por ejemplo que PSR-0 mantiene compatibilidades con características de PEAR mientras que PSR-4 las elimina. También, PSR-0 obliga a mantener una estructura de directorios similar al espacio de nombres definido mientras que PSR-4 no.

En este enlace se pueden observar más diferencias.

PSR-5: PHPDoc Standard (Status: Draft)

Este estándar no ha sido aceptado como tal y está en ‘borrador’. El propósito del mismo es definir una completa definición del estándar PHPDoc.

Hace distinción de su antecesor, el que hasta el momento es el estándar de facto PHPDoc asociado con phpDocumentor 1.x ().

PSR-5 proporciona nuevas características del lenguaje PHP y aborda algunas deficiencias del anterior.

PSR-6: Caching Interface (Status: Accepted)

La caché es la forma más común de mejorar el rendimiento de cualquier proyecto, por esto mismo, las librerías de caché son una de las características más comunes en frameworks y librerías de uso general.

La variedad existente de librerías de caché en la que cada una implementaba su propia forma de uso, creó una dificultad extra tanto a los desarrolladores que las mantenían como a los que las utilizaban. A los que las mantenían porque tenían que decidir si querían desarrollar para un grupo reducido de frameworks o adaptarse a muchos. Para los que las usaban, porque tenían que aprenderse la manera concreta en la que funcionaba cada una.

De esa dispersión de librerías y definiciones nació la necesidad de definir PSR-6, cuya pretensión y objetivo era crear un interface común para el desarrollo y uso de sistemas de caché sin necesidad de desarrollos personalizados. De manera que si quieres desarrollar una librería de caché y quieres seguir el estándar, deberías implementar PSR-6 y si vas a usar una librería de caché, asegúrate de que lo cumple.

PSR-7: HTTP message interfaces (Status: Accepted)

En este caso, PSR-7, es un conjunto de interfaces que representan mensajes y URI’s para comunicaciones HTTP. Los mensajes HTTP son la base del desarrollo web. Los navegadores y los clientes HTTP como cURL, crean un mensaje de petición HTTP para enviar al servidor web respondiendo este con un mensaje de respuesta, tamibén HTTP.

Los mensajes HTTP normalmente se abstraen el del usuario final pero los programadores necesitamos conocerlos para saber como están estructurados para acceder a ellos o manipularlos según la tarea que tengamos que desarrollar.

Los interfaces definidos en PSR-7 son los siguientes:

  • Psr\Http\Message\MessageInterface : Representa un mensaje HTTP
  • Psr\Http\Message\RequestInterface : Representa una solicitud saliente desde el lado del cliente
  • Psr\Http\Message\ServerRequestInterface : Representa una solicitud entrante desde el lado del servidor
  • Psr\Http\Message\ResponseInterface : Representa una solicitud de respuesta de salida desde el lado del servidor.
  • Psr\Http\Message\StreamInterface : Representa un stream de datos
  • Psr\Http\Message\UriInterface Value Object : Representa una URI
  • Psr\Http\Message\UploadedFileInterface : Value Object que representa un archivo subido a través de una petición HTTP

Symfony implementa PSR-7, o mejor dicho, implementaba, con uno de sus componentes. Precisamente el 2 de Marzo de 2019 su creador Fabien Potencier escribía en Twitter:

#Symfony cannot implement PSR7. So, it cannot implement PSRs based on PSR7. That simple.

Con ese mensaje, F. Potencier anunciaba que Symfony deja de implementar PSR-7 en beneficio del ecosistema de Symfony. Puedes seguir el hilo del tweet anterior para estar al tanto de lo sucedido.

El repositorio con los interfaces es el siguiente: https://github.com/php-fig/http-message

PSR-8: Huggable Interface (Status: Abandoned)

Lo de este estándar es curioso y ‘gracioso’. La verdad, después de leer varias veces por encima la especificación no me quedaba nada claro a que se refería. Busqué en internet a ver a que se refería y pronto vi que era una ‘broma’ de especificación. Si, una broma, como lo lees. Y, por lo visto, no es extrañísimo ver bromas en otras especificaciones.

Este estándar PSR-8 definía ‘abrazos’ entre objetos…entre varios objetos...la verdad, no se como no me di cuenta antes :D

Aquí dos enlaces en los que se habla del tema:
https://www.reddit.com/r/lolphp/comments/8qncp4/php_standards_wikipedia_page_psr8/
https://www.reddit.com/r/PHP/comments/3c2vs5/php_fig_psr8_implementation/

PSR-9: Security Advisories (Status: Abandoned)

Este estándar PSR-9 y el siguiente PSR-10 hablan de comunicación. Ambos hacen referencia a como se comunican los problemas de seguridad de una aplicación.

El objetivo de PSR-9 es proporcionar una estructura a la documentación que proporciona un proyecto sobre las vulnerabilidades de seguridad que se han encontrado, corregido y las que aún están pendientes.

La idea es que cualquier usuario pueda ver dicha documentación y tener una visión global sobre el estado actual de la seguridad del proyecto.

Más información: https://blog.phpdeveloper.org/2015/05/22/php-security-psr-9psr-10/

PSR-10: Security Reporting Process (Status: Abandoned)

Si PSR-9 habla sobre como documentar de forma estructurada una lista de vulnerabilidades, PSR-10 habla sobre como estandarizar el descubrimiento, la visibilidad y el acceso a dicho documento.

PSR-11: Container interface (Status: Accepted)

Este PSR-11 es bastante interesante ya que establece un estándar que define un interface común para contenedores de inyección de dependencias, es decir, normaliza como los frameworks y librerías hace uso de un contenedor para obtener objetos.

Si quieres implementar tu propio contenedor de servicios, deberías cumplir este interface, que por otro lado, es bien sencillo.

PSR-12: Extended Coding Style Guide (Status: Review)

Esta especificación de estándar extiende, expande y reemplaza a PSR-2 y de igual manera trata de una guía de estilo para la codificación con la intención final de reducir la carga cognitiva cuando un programador lee código de distintos autores.

PSR-2 fue aceptada en 2012 y PHP desde entonces ha evolucionado enormemente y con cambios en el lenguaje que tienen implicaciones para las pautas de estilos en la codificación. PSR-12 intenta cubrir toda esa nueva funcionalidad desde que PSR-2 saliera a la luz y que además pudiera estar abierta a la interpretación de cada programador.

PSR-13: Link definition interfaces (Status: Accepted)

En la propia página del estándar está bien explicado el contexto y objetivo del mismo:

Los enlaces de hipermedia se están convirtiendo en una parte cada vez más importante de la web, tanto en contextos HTML como en contextos de formato API. Sin embargo, no existe un único formato de hipermedia común ni existe una forma común de representar los enlaces entre formatos.

El objetivo de esta especificación es proporcionar a los desarrolladores de PHP una forma simple y común de representar un enlace de hipermedia independientemente del formato de serialización que se utilice, lo que permite que un sistema serialice una respuesta con enlaces de hipermedia en uno o más formatos de cable independientemente del proceso de decisión de cuáles deberían ser esos enlaces.

PSR-14: Event Dispatcher (Status: Accepted)

La generación de eventos es un mecanismo que permite a los desarrolladores añadir lógica de negocio en una aplicación de forma fácil y consistente. Por ello, el objetivo de este PSR es establecer que ese mecanismo basado en eventos sea común, de modo que las librerías y componentes que lo implementen puedan ser reutilizados con mayor libertad y comodidad.

Para conseguir este objetivo, define interfaces comunes para generar (dispatching) y manejar (handling) eventos que permitan a los programadores crear sus propias librerías que puedan interactuar con diferentes frameworks.

Más info: PSR-14: A Major Event in PHP

PSR-15: HTTP Handlers (Status: Accepted)

Antes de ver cual es el objetivo de este estándar, convendría aclarar dos conceptos:

  • Request handler: es una componente individual que procesa una petición HTTP y produce también una respuesta HTTP, ambas definidas por PSR-7. Normalmente se implementa para ir ejecutando una pila de middleware aunque también nos lo podemos encontrar como el último elemento de dicha pila ejecutando código de la aplicación. No es necesario que los “Controllers” o las acciones de dominio que resuelvan la petición implementen un request handler, aunque es posible hacerlo.
  • Middleware: es un componente individual que participa a menudo junto a otros componentes middleware en el procesado de una request haciendo comprobaciones o modificándola para generar una respuesta, bien delegando en un request handler o generándola de forma interna.

La especificación PSR-7 (HTTP messages) no contiene ninguna referencia a request handler o middleware y a partir de ahí surge PSR-15, un estándar para describir interfaces formales y comunes para “request handlers” y “middlewares” de servidores HTTP.

Algunos de los beneficios de la definición de estos interfaces son:

  • proporcionar un estándar formal para que los desarrolladores puedan usarlo.
  • habilitar un componente middleware que funcione en cualquier framework compatible.
  • eliminar la duplicidad de varios interfaces existentes definidos por distintos frameworks.
  • evitar discrepancias en las firmas de los métodos.

Más información sobre PSR-15 en este enlace: https://blog.shadowhand.me/announcing-psr-15/

PSR-16: Simple Cache (Status: Accepted)

Como se comentó anteriormente con el estándar PSR-6, la caché es la forma más común de mejorar el rendimiento en cualquier aplicación. Esto implica que las librerías de caché son una de las características más extendidas entre muchos frameworks y librerías. PSR-6 ya soluciona en parte este problema, pero de una manera muy formal y detallada que dificulta el uso en casos de uso más simples. PSR-16 es independiente de PSR-6 pero ha sido diseñado para que la compatiblidad sea lo más sencilla posible.

Este estándar define un interface más simple, para casos comunes, para implementar un driver y un elemento de caché. Las implementaciones finales que cada uno desarrolle pueden decorar los objetos con más funcionalidad pero deben implementar la funcionalidad del interface en primer lugar.

PSR-17: HTTP Factories (Status: Accepted)

Describe un estándar común para factorías que crean objetos HTTP compatibles con PSR-7 ya que este no incluye recomendaciones sobre como crear objetos HTTP dificultando el crear nuevos objetos HTTP en componentes que no estén vinculados a PSR-7.

Más información en el siguiente enlace: https://www.php-fig.org/psr/psr-17/meta/

PSR-18: HTTP Client (Status: Accepted)

Este estándar trata de describir un interface común para el envío de peticiones HTTP y la recepción de respuestas HTTP. Con PSR-7 sabemos que las peticiones y las respuestas se parecen, pero no define nada sobre como una petición debería ser enviada o recibida. Gracias a PSR-18 y a los clientes HTTP que lo implementen, los programadores podrán desarrollar librerías desacopladas de las distintas implementaciones particulares de cada cliente HTTP, lo que hará que dichas librerías sean más reutilizables.

PSR-19: PHPDoc tags (Status: Draft)

El propósito de este estándar es proporcionar un catálogo de etiquetas en el estándar PHPDoc.

Y hasta aquí la lista actual de estándares y recomendaciones PHP.


Como siempre, cualquier comentario, aclaración o sugerencia es bienvenido. Gracias por adelantado.

¡chimpún!

Bibliografía