miércoles, 20 de julio de 2016

Clases anónimas en php7

Ya ha sido liberado php7, lo que implica una renovación del lenguaje. Una de las novedades que trae son las clases anónimas.

¿Qué es una clase anónima? Simplificando, es una clase que no existe como tal pero que puede instanciar un objeto. Esto quiere decir que podemos crear un objeto a partir de una clase sin nombre, que no ha sido previamente creada.

¿Para qué nos puede servir? Veámoslo con un ejemplo.

Tenemos la siguiente clase Contract que tiene una variable de clase privada llamada $contractDate.
[code]class Contract { private $contractDate; private $contractMonths; public function __construct( string $date, int $contractMonths = 12) { $this->contractMonths = $contractMonths; $this->contractDate = new DateTime($date); } public function getEndDate() { (...) } (...) }[/code]
La variable $contactDate representa una fecha, es decir, tenemos como opciones: un String, un objeto DateTime (mejor), …

Vemos que el constructor de la clase Contract recibe dos parámetros: un String con la fecha y un integer con el número de meses de duración del contrato. Para manejar fechas lo más seguro es utilizar la propia clase de php DateTime, pero la fecha de finalización del contrato se calcularía en un método de la Clase contract getEndDate(), y esta podría guardarse en una variable de clase $endDate o devolverse calculada al vuelo en un método.

Una tercera opción sería pensar que, si la responsabilidad de las fechas está en la clase DateTime, ¿por qué no darle esa responsabilidad? Pues ya está, creemos la clase ContractDate que extendería DateTime, añadiendo sólo un método llamado getEndDate(). Tendríamos un nuevo fichero (un clase por fichero como buena práctica) con la clase ContractDate que sólo vamos a utilizar en la clase Contract pero estaría disponible en toda la aplicación. Aquí entran en juego las clases anónimas para evitar dicha situación y poder extender DateTime sin generar nuevos ficheros.

Modificamos el constructor.
[code hl="11"]class Contract { private $contractDate; const DEFAULT_CONTRACT_MONTHS = 12; public function __construct( string $date, int $contractMonths = self::DEFAULT_CONTRACT_MONTHS) { $this->contractMonths = $contractMonths; $this->contractDate = new class() extends DateTime { public function getEndDate( int $months, string $dateFormat = 'Y-m-d') : string { $date = new DateTime($this->format('Y-m-d')); $date->add(new DateInterval("P".$months."M")); $date->sub(new DateInterval("P1D")); return $date->format($dateFormat); } }; } }[/code]
Vemos que al inicializar $this->contractDate en el constructor escribimos new Class() extends DateTime { … }. Ahora tenemos un objeto de tipo clase anónima, pero a su vez es de tipo DateTime.

Ahora el método getEndDate() en la clase Contract ya no sería necesario si no queremos exponer ese dato fuera de la clase Contract.

Añadimos nuevos métodos públicos a la clase Contract. Uno de ellos se encargará de utilizar la fecha de finalización.
[code hl="13"]public function changeContractMonths(int $months) { $this->contractMonths = $months; } public function printStartDate() { echo("Start Date is ".$this->contractDate->format('Y-m-d').PHP_EOL); } public function printEndDate() { echo("End Date is ".$this->contractDate->getEndDate($this->contractMonths).PHP_EOL); }[/code]
De esta forma hemos visto como:
  • Crear un objeto a partir de una clase que no existe (anónima).
  • Extender una clase existente sin necesidad de crear una nueva clase.

Si añadimos la función notifyEach2Weeks5Times() vemos que el objeto generado a partir de la clase anónima se sigue comportando como un objeto de tipo DateTime.
[code]public function notifyEach2Weeks5Times() { $interval = new DateInterval('P2W'); $period = new DatePeriod($this->contractDate, $interval, 5, DatePeriod::EXCLUDE_START_DATE); foreach ($period as $nextDateTime) { echo $nextDateTime->format('Y-m-d').PHP_EOL; } }[/code]
Probamos la clase Contract con el código:
[code] echo("Contrato de 12 meses desde la fecha actual.".PHP_EOL); $contract = new Contract(date("Y-m-d"), 12); echo($contract->printStartDate()); echo($contract->printEndDate()); echo("Cambiamos los meses de contrato a 24.".PHP_EOL); $contract->changeContractMonths(24); echo($contract->printEndDate()); echo PHP_EOL; echo("Recordatorio cada 2 semanas 5 veces:".PHP_EOL); $contract->notifyEach2Weeks5Times(); [/code]
El resultado obtenido es:
[code]Contrato de 12 meses desde la fecha actual. Start Date is 2015-12-17 End Date is 2016-12-16 Cambiamos los meses de contrato a 24. End Date is 2017-12-16 Recordatorio cada 2 semanas 5 veces: 2015-12-31 2016-01-14 2016-01-28 2016-02-11 2016-02-25[/code]
Fichero en Git Hub

viernes, 1 de julio de 2016

¿Por qué hacer crecer la blogosfera?

¿Por qué un blog? ¿Con qué fin embarcarse en un proyecto que, con toda seguridad, no reportará beneficios al autor ni nada nuevo al mundo del desarrollo pero sí consumirá tiempo? Estas son las preguntas que seguro se habrá formulado todo aquel que haya pensado hacer algo parecido.

Podría empezar diciendo, en base a lo que cree mucha gente, que es por un ego necesitado de darse a conocer, de tener visitantes, de revolucionar el mundo del desarrollo, de ... pero me estaría engañando a mi mismo. No, la respuesta es más simple de lo que parece, todo se resume con una frase que ya muchos han debido escuchar: "si no mejoras, empeoras".

Por tanto, para ser claros, este blog no pretende, en ningún caso, ni mucho menos de forma premeditada, dar grandes lecciones de cómo desarrollar, ni mostrar nuevas técnicas que no estén en otros sitios, ni ser un lugar de referencia. El único fin es que el autor del propio blog aprenda o repase o refresque o fije conceptos que con el tiempo se acaban diluyendo. Si de paso alguien encuentra ayuda a sus problemas, que serán parecidos a los del autor, eso que sacamos todos de provecho.

Cuando leemos un libro (recomiendo hacerlo de vez en cuando) o blog sobre algún nuevo tema que desconocíamos tendemos a tratar de aprender de forma rápida, sin pausar ni digerir, a fin de cuentas según lo tenemos delante lo vamos entendiendo, por tanto, siempre, la asimilación no llega a producirse cómo debiera y el olvido llega un día y ni nos enteramos. ¿Qué mejor forma de asimilar lo aprendido que explicando a otra persona ese algo nuevo que hemos descubierto? Ese es, precisamente, el fin de este blog.

Empecemos pues.