Usando indicadores como argumentos en funciones PHP

Publicado en Snippets · 25 May 2016.

Seguramente te has encontrado en situaciones dónde se requería pasar preferencias a una función y lo habrás terminado desarrollado de las dos formás más comunes:

Haciendo que la función tenga tantos parámetros como preferencias Este modo de afrontar el problema es el más sencillo. Sin embargo, obliga casi siempre al programador cliente a especificar valores para todos los parámetros. Además, se vuelve un caos si el número de preferencias crecen o alguna llega a ser obsoleta. Aunque con las novedades que traerá pronto PHP 7.x y el constructor list, seguramente vuelva a estar en auge.

Haciendo que a la función se le pase un array como argumento con todas las preferencias. Esta opción es muy útil, sobre todo si usas intermediarios. Sin embargo, no deja de ser "black magic" y, por tanto, no fija unanimidad en los nombres de preferencias.

¿ Qué opción queda ?. Queda el uso de indicadores( o flags o banderas ). Es la opción más utilizada, ya que es necesaria para trabajar con gran parte de las funciones internas de PHP. Pese a ser la opción más utilizada, es la que menos utilizamos como programadores. Seguramente por el desconocimiento de su implementación, de ahí la creación de esta entrada. Como se ve es sencilla y práctica. Sobretodo la ventaja es que los mismos indicadores se puede utilizar en varias funciones. Es también implementable a nivel de clase( y que las constantes sean constantes de clase ).

Antes de pasar a la explicación de como se implementa, es necesario entender las operaciones a nivel de bits( o bitwase ) de PHP. Los esenciales para entender las banderas son el and(&) y el or(| ):

El operador de bit and(&) es 1 en un bit cuando el correspondiente bit de la izquierda y el de la derecha están a 1. Ejemplos( están en base2 ):

 1 & 1 = 1
 0 & 1 = 0
 1 & 0 = 0
 11 & 11 = 11
 01 & 11 = 01
 10 & 11 = 10
 111 & 101 = 101
 1111  & 1110 = 1110

El operador de bit or(|) es 1 cuando el correspondiente bit de la izquierda o el de la derecha está a 1. Ejemplos( están en base2 ):

 1 | 1 = 1
 0 | 1 = 1
 1 | 0 = 1
 0 | 0 = 0
 11 | 11 = 11
 01 | 11 = 11
 10 | 11 = 11
 10 | 10 = 10
 00 | 00 = 00
 111 | 101 = 111
 1110 | 1110 = 1110

Ahora vamos al código...

Si nos fijamos, hemos creado las distinas prefencias como constantes y le hemos asignado a cada una el valor de una potencia de dos de manera creciente(1, 2, 4... ). A la hora de pasarlas a la función hemos usado el operador or(|) dándole al parámetro $preferencias el valor(en base2): 001(1 binario de SANIT_LIMPIA_HTML) | 010( 2 binario de SANIT_ENTIDADES ) | 100( 4 binario de SANIT_DISPLAY) ) = 001 | 010 | 100 = 111

Dentro de la función, hemos averiguado si $preferencias tiene una bandera activa usando el operador and(&).

  • $limpia_html: 111($preferencias) & 001($limpia_html) = 001( en base2 ) = 1( decimal ) Como en PHP cualquier número distinto de cero es true, el resultado de la operación lógica es true y, por tanto, eso nos indica que la bandera está activa. Si no hubieramos pasado la bandera $limpia_html, $preferencias hubiera tenido valor(110) y la operación lógica hubiera sido: 110($preferencias) & 001($limpia_html) = 000( en base2 ) = 0 ( decimal ) Al haber sido cero, PHP lo considera falso y no hubiera entrado en el if.
  • $entidades: 111($preferencias) & 010($entidades) = 010( en base2 ) = 2( decimal ) Como en PHP cualquier número distinto de cero es true, el resultado de la operación lógica es true y, por tanto, eso nos indica que la bandera está activa. Si no hubieramos pasado la bandera $entidades, $preferencias hubiera tenido valor(110) y la operación lógica hubiera sido: 101($preferencias) & 010($entidades) = 000( en base2 ) = 0 ( decimal ) Al haber sido cero, PHP lo considera falso y no hubiera entrado en el if.

Como creo que ya habrá quedado claro, omito la explicación del último if y te lo dejo como ejercicio.

Haciendo un vistazo rápido a lo anterior. Vemos que para pasar indicadores o flags hay que poner las distintas contantes separadas mediante la operación a nivel de bit or(|). En el cuerpo de la función, para saber si se ha pasado una determinada bandera, hacemos operaciones binarias and(|) entre la variable que contiene el valor de todos los flags y la constante de flag que queremos comparar(ej: $preferencias & SANIT_DISPLAY ).

Para finalizar, quizás no le veas sentido reutilizar preferencias en distintas funciones y, por tanto, seas más de implementar de la primera o segunda forma. Seguramente cambies de opinión cuando sepas que las constantes de PHP de error son un ejemplo de banderas compartidas en multitud de funciones. Gracias a ello, no tenemos que aprendernos distintos nombres de indicadores para cada función sino que usamos un conjunto de valores fijos( las constantes ) como indicadores para todas las funciones.

Si te ha quedado alguna duda, no seas tímid@ y déjalo como comentario.

¡ Compártelo !
Este sitio utiliza cookies propias y de terceros para mejorar tu experiencia con el sitio web. Al continuar con la navegación consideramos que acepta su uso.