Parar de usar datetime

Especialmente para os alunos do desenvolvedor de back-end no curso PHP, eles prepararam uma tradução de um artigo interessante sobre o efeito colateral de uma ferramenta popular.





Trabalhar com datas e horários no PHP às vezes é irritante porque leva a erros inesperados no 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 

As $finishdate $startdate e $finishdate estão com pressa por três minutos, porque métodos como add () , sub() ou modify() também modificam o objeto DateTime para o qual são chamados antes de retorná-lo. O exemplo acima, é claro, mostra comportamento indesejado.

Para corrigir esse erro, copie o objeto mencionado antes de interagir com ele, por exemplo:

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

Toda vez que encontro um clone no código PHP, ele cheira a um hack da arquitetura de código com falha de alguém. Nesse caso, usamos a clonagem para evitar alterações de comportamento, mas, ao mesmo tempo, o código ficou feio e adquiriu muito ruído desnecessário.

Como alternativa, o problema pode ser resolvido convertendo a instância original do DateTime em DateTimeImmutable :

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

Por que não usar DateTimeImmutable desde o início?

Uso intransigente de DateTimeImmutable


Em vez de aplicar manualmente métodos de segurança para evitar alterações inesperadas ao passar objetos de data / hora, use DateTimeImmutable , que encapsula métodos, tornando seu código mais confiável.

 $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 

Na maioria dos casos, o conceito de data é considerado um valor, comparamos as datas pelos seus valores e, quando alteramos a data, ela se torna uma data diferente. Tudo isso se correlaciona perfeitamente com o conceito de Objeto de Valor , e uma das características importantes dos objetos de valor é que eles são imutáveis.

Estilo de codificação detalhado


A imutabilidade obriga a reatribuir explicitamente um objeto DateTimeImmutable toda vez que você interage com ele, pois ele nunca altera seu valor, retornando uma cópia. Depois de muitos anos trabalhando com o DateTime e como a mutabilidade é o padrão em muitas linguagens de programação imperativas, é difícil se livrar do hábito de usá-lo e estar em conformidade com o novo estilo de escrever código que promove o remapeamento:

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

Ferramentas de análise estatística, como o PHPStan e uma de suas extensões , podem nos avisar se omitirmos a atribuição e usarmos DateTimeImmutable incorretamente.

No entanto, esse viés cognitivo em relação à variabilidade é suprimido quando realizamos operações aritméticas nos valores dos primitivos, por exemplo: $a + 3; . Em si, isso é percebido como uma afirmação sem sentido que claramente carece de uma reatribuição: $a = $a + 3; ou $A += 3; . Seria legal usar algo assim no caso de objetos de valor, certo?

Algumas linguagens de programação possuem açúcar sintático chamado sobrecarga de operador , que permite implementar operadores em tipos e classes definidos pelo usuário para que eles se comportem exatamente como tipos de dados primitivos. Eu não me importaria se o PHP emprestasse esse truque de alguma outra linguagem de programação, e poderíamos escrever da seguinte maneira:

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

Cálculos únicos


Algumas pessoas argumentam que, em termos de desempenho, é melhor usar o DateTime , pois os cálculos são realizados na mesma área de execução. Isso é aceitável, no entanto, se você não precisar executar centenas de operações, e lembre-se de que os links para objetos antigos DateTimeImmutable serão coletados pelo coletor de lixo; na maioria dos casos, na prática, o consumo de memória não será um problema.

Bibliotecas de data / hora


O Carbon é uma biblioteca extremamente popular que estende a API de Data / Hora no PHP, adicionando um rico conjunto de recursos. Mais precisamente, estende a API da classe mutável DateTime , cuja utilização é contrária ao tópico deste artigo.

Portanto, se você gosta de trabalhar com Carbon, mas prefere a imutabilidade, sugiro que você se familiarize com o Chronos . Essa é uma biblioteca independente, originalmente baseada no Carbon, prestando atenção especial ao fornecimento de objetos de data / hora padrão imutáveis, mas também inclui opções mutáveis ​​em caso de necessidade.
Editado (07/05/2019): O Carbon tem uma opção imutável de data / hora, o que é uma grande vantagem. No entanto, a razão pela qual prefiro o Chronos é que, diferentemente do Carbon, ele incentiva e promove a imutabilidade padrão, tanto no código quanto na documentação, e esses são fatores decisivos no contexto deste artigo.

Último pensamento


DateTimeImmutable foi introduzido pela primeira vez no PHP 5.5 antigo, mas, para minha surpresa, muitos desenvolvedores estão descobrindo isso agora. Use DateTimeImmutable por padrão sempre que possível, mas lembre-se de algumas das compensações sobre as quais falei que considero mais uma questão de hábito e uma mudança de mentalidade.

Só isso. Por tradição, estamos aguardando seus comentários, amigos.

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


All Articles