Certificación Zend PHP 5.3 (III) – Arrays (II)

Tras unos días de inactividad y Hacker Cups variadas retomamos el hilo normal del blog con la segunda parte de arrays.

En este post hablaremos de algunas funciones interesantes que tiene PHP para tratar arrays y sobretodo de una de las grandes novedades en PHP 5.3, los closures.

Si veis posts sobre gente que ha estado estudiando para la certificación, veréis que mucha gente se queja o duda de la inutilidad de conocer de memoria funciones como array_map, array_splice, array_chunk. Personalmente, no comparto esta afirmación. Es posible que no recordemos todos los parámetros de las funciones, pero desde luego si las conocemos podremos hacer muchas tareas con los arrays que de otra manera haríamos a mano y, además, probablemente de forma incorrecta.

Desde luego, si tenéis pensado presentaros al examen, ya podéis coger http://php.net/manual/en/ref.array.php y estudiárosla de arriba a abajo. Recomiendo además SIEMPRE estudiar PHP con Netbeans o vuestro editor favorito y haciendo pruebas una y otra vez. Solamente así acabaréis entendiendo bien las funciones.

Funciones de ordenación

Muchas veces nos puede interesar ordenar los elementos de un array, según unos criterios. Para ello están las funciones de la familia xsort (sort, rsort, asort, arsort, ksort, krsort…) con sus parámetros.

No me voy a extender mucho sobre ellas, pero de cara al examen, dos cosas MUY importantes.

– El array que le pasamos a estas funciones va por referencia. Eso implica que se modifica el mismo y al terminar la función no podemos recuperar el estado anterior).
– Estas funciones devuelven o true o false.

Y nos podemos encontrar preguntas como:

¿Qué hace el siguiente código?

<?php
   $array = array(2, 1, 5, 0);
   echo count(sort($array));?>
Spoiler
La respuesta es 1. Sort del array, efectivamente ordena el array, pero devuelve true. Y count de algo que no es un array, devuelve 1.

Ordenaciones a medida: usort + callback

Muchas veces, necesitamos ordenar un array de objetos, según algún criterio un poco especial. La forma más sencilla es usar usort. Esta función, además del array, espera un parámetro de tipo Callable, que no es más que una función que recibe dos elementos y devolvemos un entero. Si es positivo, el primer parámetro es mayor en orden que el segundo. Si es 0 son iguales. Y si es negativo, lo contrario.

Para ilustrar esto, vamos a suponer una tienda de ropa ficticia (jejejeje) donde a veces interesa ordenar un array de objetos stock por su tallaje. Y claro, las tallas tienen un orden tipo XS, S, M, L, XL (y además pueden variar según país, añadir XXS y XXL, etc…).

Vamos a definir un array de códigos de talla ordenados, una serie de objetos desordenados y con un closure los vamos a ordenar.

<?php
/* Clase "cutrecilla" para ilustrar el ejemplo */
   class Stock {
       public $art;
       public $talla;
       public function __construct($art, $talla) {
           $this->art = $art;
           $this->talla = $talla;
       }
   }
   /* Definición del orden de las tallas */
   $ordenTallas = array('XXS', 'XS', 'S', 'M', 'L', 'XL', 'XXL');
   /* Array de objetos, no soportado por las xxsort */
   $ropa = array(
       new Stock('Pantalones', 'L'),
       new Stock('Blusa', 'M'),
       new Stock('Calcetines', 'XXS'),
       new Stock('Falda', 'XL'),
   );
   // Queremos que ordene ascendiente la ropa según las tallas
   // Vaya, que al final el orden sea Calcetines, Blusa, Pantalones, Falda
   usort($ropa, function($a, $b) use ($ordenTallas) {
       return (array_search($a->talla, $ordenTallas) - array_search($b->talla, $ordenTallas));
   });
   // Et...voilà!
   var_dump($ropa);
?>

Interesante en este caso el constructor use del closure. La variable $ordenTallas está definida en otro ámbito. Si queremos que las variables del ámbito superior estén también en el ámbito de la función, esta es la manera de pasarlo.

En cuanto al tratamiento, con array_search, devolvemos la clave en el array de tallas de la talla (es decir, 0 para XXS, 1 para XS, …) y al devolver la diferencia sabremos cómo terminarán quedando los elementos.

Lo realmente chulo del tema es que todo este código nos vale si queremos introducir nuevas tallas, ya que no hay más que modificar el array $ordenTallas. O incluso extender el código para diferentes países o tipos de mercancía solamente cambiando el array de configuración.

Veréis también que el último elemento del array $ropa tiene una ‘,’ al final, aunque no hay nada detrás. Esto no es una errata, está soportado por PHP y de hecho es una manía mía. Con ello, si alguien poco técnico entra a tocar el array para añadir un nuevo valor, probablemente hará CTRL-C, CTRL-V debajo y editará el valor. De esta manera, no tiene que recordar la , del final. Parece una tontería pero no lo es :).

Funciones para tratar los arrays como un haystack

Estas funciones son bastante útiles para recoger los datos de la Hacker Cup y especialmente cuando recibimos de, por ejemplo, un fichero de texto. Tenemos:
– array_shift: Nos devuelve el primer elemento del array y deja al array sin el mismo.
– array_unshift: Introduce el elemento en la posición 0 del array y si es necesario, desplaza todas las claves numéricas
– array_push: Introduce el elemento al final del array.
– array_pop: Devuelve el último elemento del array y lo elimina del mismo.

Otras funciones que uso a menudo

– shuffle: Reordena el array de forma aleatoria, muy útil!
– array_map: Aplica un tratamiento a todos los elementos de un array. Por ejemplo:

<?php
   // Eliminar espacios de los super-globales
   array_map('trim', $_POST);
   array_map('trim', $_GET);
?>

– array_fill: Para rellenar varios elementos con el mismo valor. A veces es útil.
– array_unique: Viene a ser una especie de “SELECT DISTINCT”.

Cosas que encontraréis 99% en el examen y no he comentado antes

– array_slice: Viene a ser una especie de substring, aplicado a los arrays.
– array_splice: Nunca sabré de memoria lo que hace, pero es probable que os la encontréis.
– extract: Convierte el par ‘clave’ => ‘valor’ a $clave = ‘valor’.

¿Qué da esto?

<?php
  $array = array('a' => 'John', 
                       'b' => 'Coggeshall', 
                       'c' => array('d' => 'John', 
                                        'e' => 'Smith')
                       ); 
  function something($array) {
    extract($array); 
    return $c['e']; 
  } 
  print something($array);
?>
Spoiler
Da Smith. Extract en este contexto es equivalente a escribir $a = ‘John’; $b = ‘Coggeshall’, $c = array(‘d’ => ‘John’, ‘e’ => ‘Smith’));

– list: Asigna a variables los elementos del array.

What would you replace ??????? with, below, to make the string Hello, World! be displayed?

<?php
function myfunction() {
???????
print $string;
}
myfunction("Hello, World!");
?>
Spoiler
Se puede, se puede… haciendo por ejemplo list($string) = func_get_args();

Pues esto es todo por hoy, próximamente más cositas de PHP!

You may also like...