Berhenti menggunakan datetime

Khusus untuk siswa kursus "Pengembang PHP Backend", mereka menyiapkan terjemahan artikel yang menarik tentang efek samping alat populer.





Bekerja dengan tanggal dan waktu dalam PHP kadang-kadang menjengkelkan karena menyebabkan bug yang tidak terduga dalam kode:

$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 

Baik fungsi $startdate dan $finishdate terburu-buru selama tiga menit, karena metode seperti add () , sub() atau modify() juga memodifikasi objek DateTime yang dipanggil sebelum mengembalikannya. Contoh di atas, tentu saja, menunjukkan perilaku yang tidak diinginkan.

Kami dapat memperbaiki kesalahan ini dengan menyalin objek yang dirujuk sebelum berinteraksi dengannya, misalnya:

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

Setiap kali saya menemukan klon dalam kode PHP, baunya seperti retas arsitektur kode gagal seseorang. Dalam hal ini, kami menggunakan kloning untuk menghindari perubahan perilaku, tetapi pada saat yang sama, kode menjadi jelek dan memperoleh banyak suara yang tidak perlu.

Atau, masalah dapat diatasi dengan mengonversi instance DateTime asli ke DateTimeImmutable :

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

Mengapa tidak menggunakan DateTimeImmutable dari awal?

Penggunaan DateTimeImmutable tanpa kompromi


Alih-alih menerapkan metode keamanan secara manual untuk mencegah perubahan tak terduga saat melewati objek tanggal / waktu, gunakan DateTimeImmutable , yang merangkum metode, membuat kode Anda lebih dapat diandalkan.

 $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 

Dalam kebanyakan kasus, konsep tanggal dianggap sebagai nilai, kami membandingkan tanggal dengan nilainya, dan ketika kami mengubah tanggal, itu menjadi tanggal yang berbeda. Semua ini berkorelasi sempurna dengan konsep Object Value , dan salah satu karakteristik penting dari objek value adalah mereka tidak dapat diubah.

Gaya pengkodean terperinci


Immutability memaksa Anda untuk secara eksplisit menetapkan kembali objek DateTimeImmutable setiap kali Anda berinteraksi dengannya, karena itu tidak pernah mengubah nilainya, alih-alih mengembalikan salinan. Setelah bertahun-tahun bekerja dengan DateTime dan karena mutabilitas adalah default di banyak bahasa pemrograman imperatif, sulit untuk menghilangkan kebiasaan menggunakannya dan menyesuaikan dengan gaya penulisan kode baru yang mempromosikan pemetaan ulang:

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

Alat analisis statistik, seperti PHPStan dan salah satu ekstensinya , dapat memperingatkan kita jika kita mengabaikan tugas dan menggunakan DateTimeImmutable salah.

Namun, bias kognitif terhadap variabilitas ditekan ketika kita melakukan operasi aritmatika pada nilai-nilai primitif, misalnya: $a + 3; . Dalam dirinya sendiri, ini dianggap sebagai pernyataan tidak berarti yang jelas tidak memiliki penugasan kembali: $a = $a + 3; atau $A += 3; . Akan lebih baik menggunakan sesuatu seperti ini dalam kasus objek nilai, bukan?

Beberapa bahasa pemrograman memiliki gula sintaksis yang disebut operator overloading, yang memungkinkan Anda untuk mengimplementasikan operator dalam tipe dan kelas yang ditentukan pengguna sehingga mereka berperilaku seperti tipe data primitif. Saya tidak keberatan jika PHP meminjam trik ini dari beberapa bahasa pemrograman lain, dan kita dapat menulis sebagai berikut:

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

Perhitungan satu kali


Beberapa orang berpendapat bahwa dalam hal kinerja, lebih baik menggunakan DateTime , karena perhitungan dilakukan dalam area eksekusi yang sama. Namun ini dapat diterima, jika Anda tidak perlu melakukan ratusan operasi, dan Anda ingat bahwa tautan ke objek DateTimeImmutable lama akan dikumpulkan oleh pengumpul sampah, dalam banyak kasus dalam praktiknya, konsumsi memori tidak akan menjadi masalah.

Perpustakaan tanggal / waktu


Carbon adalah pustaka yang sangat populer yang memperluas API Tanggal / Waktu dalam PHP, menambahkan serangkaian fitur yang kaya. Lebih tepatnya, ia memperluas API dari kelas yang bisa berubah DateTime , penggunaannya yang bertentangan dengan topik artikel ini.

Oleh karena itu, jika Anda menikmati bekerja dengan Karbon tetapi lebih memilih kekekalan, saya sarankan Anda membiasakan diri dengan Chronos . Ini adalah pustaka mandiri, yang pada awalnya berbasiskan Carbon, memberikan perhatian khusus untuk menyediakan objek tanggal / waktu default yang tidak dapat diubah, tetapi juga mencakup opsi yang bisa berubah jika diperlukan.
Diedit (07/05/2019): Ternyata Carbon memiliki opsi tanggal / waktu yang tidak dapat diubah, yang merupakan nilai tambah besar. Namun, alasan saya lebih suka Chronos adalah bahwa, tidak seperti Carbon, ini mendorong dan mempromosikan ketidakmampuan standar, baik dalam kode dan dalam dokumentasi, dan ini adalah faktor penentu dalam konteks artikel ini.

Pemikiran terakhir


DateTimeImmutable pertama kali diperkenalkan kembali di PHP 5.5 kuno, tetapi yang mengejutkan saya, banyak pengembang baru menemukannya. Gunakan DateTimeImmutable secara default bila memungkinkan, tetapi perlu diingat beberapa pertukaran yang saya bicarakan yang saya pikir lebih merupakan masalah kebiasaan dan perubahan pola pikir.

Itu saja. Secara tradisi, kami menunggu komentar Anda, teman-teman.

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


All Articles