Dejar de usar datetime

Especialmente para los estudiantes del curso "Backend PHP Developer", prepararon una traducción de un artículo interesante sobre el efecto secundario de una herramienta popular.





Trabajar con fechas y horas en PHP a veces es molesto porque conduce a errores inesperados en el código:

$startedAt = new DateTime('2019-06-30 10:00:00'); $finishedAt = $startedAt->add(new DateInterval('PT3M')); var_dump($startedAt->format('Ymd H:i:s')); //2019-06-30 10:03:00 var_dump($finishedAt->format('Ymd H:i:s')); //2019-06-30 10:03:00 

Las $startdate y $finishdate tienen prisa durante tres minutos, porque los métodos como add () , sub() o modify() también modifican el objeto DateTime para el que se llama antes de devolverlo. El ejemplo anterior, por supuesto, muestra un comportamiento no deseado.

Podemos corregir este error copiando el objeto al que se hace referencia antes de interactuar con él, por ejemplo:

 $startedAt = new DateTime('2019-06-30 10:00:00'); $finishedAt = clone $startedAt; $finishedAt->add(new DateInterval('PT3M')); 

Cada vez que me encuentro con un clon en código PHP, huele a un truco de la arquitectura de código fallida de alguien. En este caso, utilizamos la clonación para evitar cambiar el comportamiento, pero al mismo tiempo, el código se volvió feo y adquirió mucho ruido innecesario.

Alternativamente, el problema se puede resolver convirtiendo la instancia original de DateTime a DateTimeImmutable :

 $startedAt = new DateTime('2019-06-30 10:00:00'); $finishedAt = DateTimeImmutable::createFromMutable($startedAt)->add(new DateInterval('PT3M')); 

¿Por qué no usar DateTimeImmutable desde el principio?

Uso intransigente de DateTimeImmutable


En lugar de aplicar manualmente métodos de seguridad para evitar cambios inesperados al pasar objetos de fecha / hora, use DateTimeImmutable , que encapsula los métodos, haciendo que su código sea más confiable.

 $startedAt = new DateTimeImmutable('2019-06-30 10:00:00'); $finishedAt = $startedAt->add(new DateInterval('PT3M')); var_dump($startedAt->format('Ymd H:i:s')); //2019-06-30 10:00:00 var_dump($finishedAt->format('Ymd H:i:s')); //2019-06-30 10:03:00 

En la mayoría de los casos, el concepto de una fecha se considera como un valor, comparamos las fechas por sus valores, y cuando cambiamos la fecha, se convierte en una fecha diferente. Todo esto se correlaciona perfectamente con el concepto de Objeto de valor , y una de las características importantes de los objetos de valor es que son inmutables.

Estilo de codificación detallada


La inmutabilidad lo obliga a reasignar explícitamente un objeto DateTimeImmutable cada vez que interactúa con él, ya que nunca cambia su valor, sino que devuelve una copia. Después de muchos años de trabajar con DateTime y debido a que la mutabilidad es la predeterminada en muchos lenguajes de programación imperativos, es difícil deshacerse del hábito de usarlo y cumplir con el nuevo estilo de código de escritura que promueve la reasignación:

 $this->expiresAt = $this->expiresAt->modify('+1 week'); 

Las herramientas de análisis estadístico, como PHPStan y una de sus extensiones , pueden advertirnos si omitimos la asignación y usamos DateTimeImmutable incorrectamente.

Sin embargo, tal sesgo cognitivo hacia la variabilidad se suprime cuando realizamos operaciones aritméticas en los valores de las primitivas, por ejemplo: $a + 3; . En sí mismo, esto se percibe como una declaración sin sentido que claramente carece de una reasignación: $a = $a + 3; o $A += 3; . Sería genial usar algo como esto en el caso de los objetos de valor, ¿verdad?

Algunos lenguajes de programación tienen un azúcar sintáctico llamado sobrecarga de operadores , que le permite implementar operadores en tipos y clases definidos por el usuario para que se comporten como los tipos de datos primitivos. No me importaría si PHP tomó prestado este truco de algún otro lenguaje de programación, y podríamos escribir de la siguiente manera:

 $this->expiresAt += '1 week'; 

Cálculos únicos


Algunas personas argumentan que, en términos de rendimiento, es mejor usar DateTime , ya que los cálculos se realizan dentro de la misma área de ejecución. Sin embargo, esto es aceptable si no necesita realizar cientos de operaciones y recuerda que el recolector de basura recopilará enlaces a objetos antiguos DateTimeImmutable , en la mayoría de los casos, en la práctica, el consumo de memoria no será un problema.

Bibliotecas de fecha / hora


Carbon es una biblioteca extremadamente popular que extiende la API de fecha / hora en PHP, agregando un rico conjunto de características. Más precisamente, extiende la API de la clase mutable DateTime , cuyo uso es contrario al tema de este artículo.

Por lo tanto, si disfruta trabajar con Carbon pero prefiere la inmutabilidad, le sugiero que se familiarice con Chronos . Esta es una biblioteca independiente, que originalmente se basó en Carbon, prestando especial atención a proporcionar objetos de fecha / hora predeterminados inmutables, pero también incluye opciones mutables en caso de necesidad.
Editado (05/07/2019): Resultó que Carbon tiene una opción de fecha / hora inmutable, que es una gran ventaja. Sin embargo, la razón por la que prefiero Chronos es que, a diferencia de Carbon, alienta y promueve la inmutabilidad predeterminada, tanto en código como en documentación, y estos son factores decisivos en el contexto de este artículo.

Ultimo pensamiento


DateTimeImmutable se introdujo por primera vez en PHP 5.5 antiguo, pero para mi sorpresa, muchos desarrolladores lo están descubriendo en este momento. Use DateTimeImmutable de forma predeterminada siempre que sea posible, pero tenga en cuenta algunas de las compensaciones de las que hablé que creo que son más una cuestión de hábito y un cambio de mentalidad.

Eso es todo. Por tradición, esperamos sus comentarios, amigos.

Source: https://habr.com/ru/post/464253/


All Articles