domingo, 5 de septiembre de 2010

Gestión de parámetros en funciones con PHP

La mejor forma de separar y organizar nuestro código es mediante el uso de funciones. PHP permite la definición de funciones con o sin parámetros, estos pueden ser opcionales o como veremos a continuación pasarlos a la función sin previamente haber sido definidos.

//definimos una funcion
//en principio no espera parametros
function no_params() {
  echo "Número de parámetros pasados a la función: ";
  echo func_num_args();
  echo "<br />";
  //obtenemos un array con todos
  //los parámtros pasados
  $args = func_get_args();
  foreach ($args as $arg) {
    echo $arg."<br />";
  }
}
//pero al llamarla le pasamos una
//lista de parámetros
no_params("param1", "param2", 12);
//con lo que obtenemos en pantalla
param1
param2
12

Expresiones regulares con PHP

Recordamos algunas reglas básicas para el uso y manejo de expresiones regulares en PHP.

Carácter Significado
\ Carácter de escape
^ Coincidencia al principio
$ Coincidencia al final
. Coincidencia con cualquier carácter excepto nueva línea \n
| Opción alternativa OR
( Inicio subpatrón
) Final subpatrón
* Se repite 0 o más veces
+ Se repite 1 o más veces
{ Inicio cuantificador min/max
} Final cuantificador min/max
? Subpatrón opcional
Carácteres especiales utilizados detro de corchetes
\ Carácter de escape
^ No, utilizado en una posición inicial
- Indica rangos de carácter

Veamos algunos ejemplos prácticos del uso de esta sintaxis con la ayuda de algunas funciones de PHP para buscar o reemplazar cadenas.

Podemos comprobar la existencia de subcadenas que coincidan con el patrón de la expresión regular con las funciones ereg() y eregi(). La única diferencia entre ellas es que eregi() es "case insensitive", es decir no diferencia entre mayúsculas y minúsculas, mientras que ereg() sí.

$cadena = "http://www.google.com";
ereg('^(http|https):\/\/', $cadena);
//devuelve true ya que la cadena
//empieza por http://

ereg_replace('^(http|https):\/\/', 'https://', $cadena);
//sustituimos http:// por https://

Otro función útil para el manejo de expresiones regulares con PHP es split. Con su ayuda podemos dividir cadenas y obtener un array con las subcadenas resultantes.

$cadena = "http://www.google.com";
$arr = split('\/\/|\.', $cadena);
while (list($k, $v) = each($arr)) {
 echo $v .'<br />'; 
}
//retorna
http:
www
google
com

Para realizar una comparación global de una expresión regular utilizamos la función preg_match_all() que buscará todas las coincidencias de la expresión regular dada y las introduce en un array en el orden que especifiquemos opcionalmente.

$cadena = "En el año 1942 Cristobal Colon descubrió américa. ";
$cadena .= "Murió en el 1506.";
preg_match_all("/[0-9]{4}/", $cadena, $coincidencias);
foreach ($coincidencias as $a) {
  foreach ($a as $v) {
    echo $v . '<br />'; 
  }
}
//imprime
1942
1506
sábado, 4 de septiembre de 2010

Sustitución de subcadenas con PHP

Más recursos para el manejo de strings str_replace() y substr_replace(). Sirven básicamente para buscar y reemplazar cadenas.

//podemos utilizar una variable o un array
//para indicar los terminos buscados
$arr_busca = array("hola", "clavel", "corazón");
$arr_reemplaza = array("adiós", "flor", "amor");
str_replace($arr_busca, $arr_reemplaza, "hola clavel, adiós corazón");
//resulta
adiós flor, adiós amor

Del mismo modo la función substr_replace permite buscar y reemplazar una subcadena de una cadena en función de su posición. Espera los parámetros: cadena, sustitución, inicio y longitud. Si el valor del parámetro inicio es positivo o 0 el desplazamiento se calcula desde el principio, si es negativo se establece con respecto al final de la cadena. El valor de longitud representa el número de caracteres que será sustituido, si es 0 la cadena de sustitución se inserta sin sobreescribir la cadena existente, si este es negativo representa el punto donde se dentendrá la sustitución.

$var = substr_replace($str, 'hola', 2, 0); 

Funciones prácticas para manipular cadenas con PHP

La manipulación de cadenas de texto es una de las tareas más comunes a la hora de trabajar con PHP. Este lenguaje incorpora de forma nativa un buen número de funciones que nos facilitan enormemente el manejo de strings. Vamos a repasar algunas de estas las funciones para manipular cadenas más comunes.

Función Descripción
strtoupper() Convierte la cadena pasada como parámetro en mayúsculas.
strtolower() Convierte la cadena en minúsculas.
ucfirst() Pone en mayúsculas el primer carácter de la cadena.
ucwords() Pone en mayúsculas la primera letra de cada palabra.
addslashes() Escapa carácteres especiales agregando la barra invertida correspondiente.
stripslashes() Elimina las barras de escape.

Ejemplos de uso de otras funciones.

//substr() retorna una subcadena a partir
//de los puntos indicados como parámetro incial y final
$var = substr("hola que tal", 1);
//devuelve
ola que tal

//si el valor inicio es negativo
//devuelve la parte final de la cadena
//con los caracteres indicados
substr("hola que tal", -3);
//devueve
tal

//el parámetro longitud sirve para
//indicar el número de carácteres a devolver
//si es positivo o la posición final de la
//secuencia de retorno si es negativo
substr("hola que tal", 0, 4);
//devuelve
hola
substr("hola que tal", 0, -4);
//devuelve
hola que

Para buscar subcadenas dentro de otras cadenas utilizamos strstr(), que espera que le pasemos 2 parámetros, primero el texto donde buscar y segundo el texto buscado. Devuelve el texto pasado como parámetro número 1 desde la posición donde se haya encontrado la cadena buscada o false en caso de no encontrarla.

$cadena = "En un lugar de la mancha";
echo strstr($cadena, "lugar");
//devuelve
lugar de la mancha

Para obtener la posición de una subcadena utilizaremos strpos() y strrpos() que funcionan básicamente igual que strstr() con la diferencia de que en lugar de devolver una subcadena devuelve su posición numérica.

$cadena = "En un lugar de la mancha";
echo strpos($cadena, "un");
//imprime 3 ya que 3 es la
//posición que ocupa "un" en la
//cadena principal

//podemos emplear un tercer parámetro
//que sirve para indicar la posición
//a partir de la cual comenzamos a buscar
echo strpos($cadena, "n", 3);
//devuelve 4 ya que no se ha tenido en cuenta
//la primera n de "En"

La función strrpos() realiza la misma tarea pero retorna la posición de la última coincidencia en lugar de la primera. Estas dos funciones devolverán false si no encuentran la subcadena buscada. Importante: utilizar comparaciones estrictas y el operador === para evitar falsos positivos.

Manejo de strings con PHP

Vamos a ver algunas funciones útiles para el manejo y formateo de cadenas en PHP.

Para aplicar un formato personalizado PHP nos ofrece algunas opciones, entre ellas cabe destacar printf() y todas sus variantes como sprintf(), vprintf() y vsprintf(). Su uso es sencillo si conocemos los distintos códigos de formato que debemos aplicar.

$npedido = 129;
$total = 202.55;
printf("Total del pedido número %u = $.2f €", $npedido, $total);
//en este caso estamos imprimiendo la cadena:
//Total del pedido número 129 = 202.55 €

La diferencia entre printf() y sprintf() es que la primera imprime el resultado y la segunda simplemente lo devuelve. Además, es posible utilizar la numeración de elementos para no tener que depender del orden de las especificaciones de conversión al pasar las variables a la función o para poder repetir alguna de ellas.

printf("%1$/u - Total del pedido número %1$/u = %\2$.2f €",
  $npedido, $total);
//imprimiria en la página:
//129 - Total del pedido número 129 = 202.55 €

Del mismo modo, podemos pasar un array en lugar de un número concreto de variables. Para ello debemos utilizar la función vprintf().

$arr = array(129, 202.55);
vprintf("Total del pedido número %u = $.2f €", $arr);

En esta tabla se indican los diferentes códigos de especificación de conversión.

Tipo Significado
b Interpretado como un entero y se imprime como un número binario
c Interpretado como un entero y se imprime como un carácter
d Interpretado como un entero y se imprime como un número decimal
f Interpretado como un doble y se imprime como un número con coma flotante
o Interpretado como un entero y se imprime como un número octal
s Interpretado como una cadena y se imprime como una cadena
u Interpretado como un entero y se imprime como un decimal sin signo
x Interpretado como un entero y se imprime como un número decimal con minúsculas para los dígitos a-f
X Interpretado como un entero y se imprime como un número hexadecimal con mayúsculas para los dígitos A-F
jueves, 2 de septiembre de 2010

Contar elementos de un array con PHP

En muchas ocasiones se hace muy necesario obtener el número total de elementos incluidos dentro de una matriz. Existen en PHP varias funciones que nos devuelven esta información la más popular es count() que cuenta el número de items del array pasado como parámetro. Con la función sizeof obtendremos el mismo resultado.

Mención aparte merece array_count_values(), esta otra función lo que hace es contar el número de veces que se repite cada valor único dentro de la matriz que le pasemos como parámetro. Retorna un array asociativo similar a una tabla de frecuencia.

$arr = array("a", "b", "b", "c", "d", "d", "d");
$fr = array_count_values($arr);
//si recorremos este segundo array
foreach ($fr as $item => $veces) {
  echo $item.': '.$veces.'<br />';
}
//obtendremos
a: 1
b: 2
c: 1
d: 3
miércoles, 1 de septiembre de 2010

Formas de recorrer arrays con PHP

PHP dispone de múltiples estructuras para el manejo de bucles y por ende pone a nuestra disposición una serie de cómodas alternativas para recorrer y manejar arrays. Veamos unos cuantos ejemplos.

//matrizes indexadas numéricamente
$arr = range('a', 'e');
for ($i=0;$i<5;$i++) {
  echo $arr[$i];
}
//otra forma seria foreach
foreach ($arr as $letra) {
  echo $letra;
}

//matrices asociativas
$multiarr = array(
  'nombre'=>'David',
  'genero'=>'masculino',
  'edad'=>'36'
);

foreach ($multiarr as $clave=>$valor) {
  echo $clave.': '.$valor;
}
//otra forma de recorrer matrices asociativas
//es utilizando las instrucciones list() y each()
while ($el = each($multiarr)) {
  echo $el['key'].': '.$el['value'];
  //el indice key es equivalente a 0
  //y value a 1

}
//la función list() nos brinda
//la opción convertir los elementos key y value (0, 1)
//en 2 nuevas variables
while (list($clave, $valor) = each($multiarr)) {
  echo $clave.': '.$valor;
}

La función each() obliga a resetear con reset() el array una vez recorrido si lo queremos volver a utilizar.

//reubicamos el elemento actual
//al principio de la matriz
//antes de volverlo a recorrer
reset($multiarr);

Una array multidimensional es aquel que a su vez contiene en cada ubicación otras matrices. El concepto básico es similar al de una tabla con filas y columnas.

//matriz bidimensional
$arr = array(
  array('David','masculino',36),
  array('Felipe','masculino',26),
  array('Andrea','femenino',21)
);
//podemos recorrer este array utilizando
//un bucle for y un pequeño truco para
//acceder al indice mayor del array tanto
//de las filas como de las columnas
$filas = count($arr, 0);
//redondeo al alza con ceil()
$columnas = ceil(count($arr,1)/count($arr,0))-1);
echo 'Este arreglo tiene '.$filas.' filas y '.$columnas.' columnas';
for ($fil = 0; $fil < $filas; $fil++) {
  for ($col = 0; $col < $columnas; $col++) {
    echo $arr[$row][$col];
  }
}

Tal vez prefiramos almacenar los registros utilizando columnas con nombre, de nuevo echamos mano de las matrices asociativas y almacenamos el mismo conjunto de datos anterior pero con nombres en lugar de números por cada row.

$arr = array(
  array('Nombre'=>'David', 'Genero'=>'masculino', 'Edad'=>36),
  array('Nombre'=>'Felipe', 'Genero'=>'masculino', 'Edad'=>26),
  array('Nombre'=>'Andrea', 'Genero'=>'femenino', 'Edad'=>21)
);
for ($row = 0; $row < count($arr, 0); $row++) {
  foreach ($arr[$row] as $key => $value) {
    echo $key.': '.$value.'<br />';
  }
}
//o como hemos visto anteriomente
//podemos emplear list() y each() para
//asignar los distintos valores a las
//variables $key y $value para un más
//fácil manejo
for ($row = 0; $row < count($arr, 0); $row++) {
  while (list($key, $value) = each($arr[$row])) {
    echo $key.': '.$value.'<br />';
  }
}

Seguimos añadiendo dificultad a medida que vamos aumentando las dimensiones de nuestros arreglos o arrays. PHP no tiene límites en relación al número de dimensiones que podemos añadir, vamos a ver como recorreríamos un array de 3 dimensiones.

$arr = array(
  array(
    array('USER', 'David', 'masculino', 100),
    array('USER', 'Felipe', 'masculino', 26),
    array('USER', 'Andrea', 'femenino', 21)
  ),
  array(
    array('ADMIN', 'Sandra', 'femenino', 35),
    array('ADMIN', 'Pepito', 'masculino', 45),
    array('ADMIN', 'Maria', 'femenino', 19)
  ),
  array(
    array('CLIENT', 'Juan', 'masculino', 28),
    array('CLIENT', 'Olivia', 'femenino', 23),
    array('CLIENT', 'Santiago', 'masculino', 63),
    array('CLIENT', 'Vicen', 'femenino', 37)
  )
);
for ($capa = 0; $capa < count($arr, 0); $capa++) {
  echo 'Capa: ' . $capa . '<br />';
  for ($fil = 0; $fil < count($arr[$capa], 0); $fil++) {
    for ($col = 0; $col < count($arr[$capa][$fil], 0); $col++) {
      echo $arr[$capa][$fil][$col] . ' - ';
    }
    echo '<br />'; 
  } 
}

Y ya que andamos jugueteando con los arrays veamos ahora una forma de seleccionar una imagen de forma aleatoria de entre todas las que nos encontremos con la extensión jpg en un directorio dado.

$path = "img";
$d = opendir($path);
while ($img = readdir($d)) {
  if (pathinfo($path . $img, PATHINFO_EXTENSION) == 'jpg')
    $fotos[] = $img;
}
closedir($d);
shuffle($fotos);
echo "<img src=\"img/$fotos[0]\" />";

Podemos movernos o recorrer arrays con un mayor control utilizando algunas funciones específicas como each(), current(), reset(), end(), next(), pos(), prev().

Como ejemplo vamos a recorrer una matriz de forma inversa con la ayuda de end() y prev().

//situamos el puntero al final del array
$val = end($array);
//empleamos un bucle while y la función
//prev() para mover el puntero de forma inversa
while ($val) {
  echo $val;
  $val = prev($array);
}

Tenemos la posibilidad mediante array_walk() de aplicar una función personalizada a cada elemento de un array. Esto nos permite modificar o emplear cada item del arreglo de una misma forma. Esta función espera como parámetros, el array con el que trabajar, la función personalizada y opcionalmente un parámetro que pasaríamos a nuestra función.

//mostramos en pantalla el resultado
//de multiplicar cada elemento por el factor pasado
//como parámetro a nuestra función multiplicadora
$array = range(1, 10);
function multiplicador($value, $key, $factor) {
  echo $value * $factor;
}
array_walk($array, 'multiplicador', 3);