سلام دوستان، امشب داشتم یه مطلبی رو تو سایت medium راجع به موضوع کلاس های immutable مطالعه میکردم؛ متوجه شدم که داخل منابع فارسی مطلب به درد بخوری وجود نداره، پس تصمیم گرفتم این مطلب رو بنویسم و خب میخوام از این به بعد بنویسم تا بیشتر تو ذهنم بمونه :)
یه شعار خیلی جالبی تو فوروم های برنامه نویسی گاهی دیده میشه که میتونه جالب باشه و در واقع میشه گفت این مطلب از اونجا نشأت گرفته و اونم اینه:
immutability helps reduce bugs
«تغییرناپذیری کمک میکنه که باگ ها کم بشن»
این یعنی چی؟ ببینین ما مثالمون رو با دو تا کتابخونه معروف تو PHP شروع میکنیم که احتمالا با یکیش هم کار کرده باشین. کتابخونه Carbon و Chronos که هر دو برای کار کردن با date هستن. کتابخونه Carbon که تو لاراول خیلی دیدیمش و کتابخونه کرونوس هم به نظر از پروژه CakePHP منشأ گرفته.
نکته مهمی که باید بدونیم در مورد تفاوت این دو تا کتابخونه هست. کربن میوتبل (تغییرپذیر) و کرونوس ایمیوتبل (تغییرناپذیر) هست که در ادامه بیشتر راجع بهش توضیح میدیم.
اول از همه کربن رو بررسی میکنیم، بیاین یه مثال از جنس کد ببینیم تا بیشتر آشنا بشیم.
$now = \Carbon\Carbon::createFromDate(2017, 6, 13); echo $now; // 2017-06-13 04:11:44 $twomonthslater = $now->addMonths(2); echo $twomonthslater; // 2017-08-13 04:11:44 echo $now; // 2017-08-13 04:11:44 Uh-oh!!
تیکه کد بالا میاد و از تاریخی که بهش دادیم یعنی ۲۰۱۷/۰۶/۱۳ یه آبجکت یا شی میسازه(خط ۱).
خب تا اینجا رفتارش خیلی عادی و معمولی هست
بعد اومدیم و زمان فعلی رو نمایش دادیم (خط ۲).
نکته مهمی که وجود داره تو خط ۳ هست یعنی زمانی که ما میایم و ۲ ماه رو به زمانی که داشتیم اضافه میکنیم و درواقع آبجکتمون رو modify میکنیم. اتفاقی که میفته اینه که این کلاس تو خط ۳ نمیاد یه شی جدید بسازه و ۲ ماه بهش اضافه کنه و اون رو داخل متغیر twomonthslater$ بریزه. در واقع میاد خود شی اصلی که همون now$ هست رو تغییر میده و اینجاست که به مشکل میخوریم.
ممکنه بپرسین از کجا به این موضوع پی میبریم؟ از خط ۴ و ۵. ما اومدیم و یه بار زمان جدیدی که ۲ ماه بهش اضافه کردیم رو چاپ کردیم و تو خط بعدش اومدیم متغیر اولیه مون رو چاپش کردیم و در کمال تعجب میبینیم که متغیر اولیه یعنی now$ هم تغییر کرده :| Uh-oh!!
این موضوع کلی مشکل ممکنه برای برنامه مون ایجاد کنه و باعث بشه ما زمان های خیلی طولانی رو صرف دیباگ و پیدا کردن مشکل بشیم، ممکنه ما شی میوتبل مون رو به یه تابع یا متد پاس بدیم و اون متد بیاد و یه سری تغییراتی روش اعمال کنه و شی قبلیمون دیگه همون قبلی نیست و عوض شده به همین سادگی :]
خب واسه حل این مشکل باید چیکار کنیم؟ باید از کلاس های ایمیوتبل یا تغییرناپذیر استفاده کنیم. یعنی کلاس هایی که شی اصلی رو تغییر نمیدن و موقعی که بخوایم یه عملیات modify مثل addMonth و ... رو روش صدا بزنیم میاد و یه شی جدید میسازه و با اون قبلی کاری نداره. این کاری هست که کرونوس میکنه. به مثال زیر دقت کنین:
$chronosNow = Cake\Chronos\Chronos::create(2017,06,13); echo $chronosNow; // 2017-06-13 04:11:44 $chronosTwomonthslater = $chronosNow->modify('+2 months'); echo $chronosTwomonthslater; // 2017-08-13 04:11:44 echo $chronosNow; // 2017-06-13 04:11:44
اینجا بر خلاف بالا ما اومدیم و از کتابخونه کرونوس استفاده کردیم. و عین قبل modify کردیم و ۲ ماه بهش اضافه کردیم و هر دو متغیر یعنی متغیر اولیه chronosNow$ و متغیر chronosTwomonthslater$ رو چاپ کردیم. میبینیم که تغییری تو شی اولیه مون ایجاد نشده :) میتونیم شاد و خوشحال ازش همه جا استفاده کنیم بدون این که نگران این باشیم که ممکنه تغییر کنه و باگ پیش بیاره.
این موضوع به تیتر پست (مقایسه DateTimeImmutable و DateTime در PHP) چه ارتباطی داشت؟
توی PHP دو کلاس وجود داره که این خاصیت ها رو دارن DateTimeImmutable و DateTime و بسته به شرایطی که داخلش قرار دارین باید تصمیم بگیرین که از کدوم یکی استفاده کنین.
ممنون میشم اگر انتقادی یا پیشنهادی وجود داره حتما بگین :)
در واقع میشه گفت این پست جمع بندی نکاتی هست که از لینک های زیر متوجه شدم.
https://medium.com/@codebyjeff/whats-all-this-immutable-date-stuff-anyway-72d4130af8ce
https://stackoverflow.com/questions/67536245/datetimeimmutable-vs-datetime
https://www.php.net/manual/en/class.datetimeimmutable.php
https://www.php.net/manual/en/class.datetime.php