نسخه جدید php یعنی 8.1 منتشر شده و واقعا عالیه امکانات جدید و پرفورمنس بهتر
و یکی از هیجان انگیز ترین فیچری که اضافه شده کامپایلر جدید یعنی JIT هست. این نسخه در تاریخ 25 نوامبر 2021 منتشر شده.
اینجا میخواهیم که چنتا از امکانات خوب و واقعا کاربردی رو که این نسخه به ارمغان میاره رو باهم بررسی کنیم و شروع به استفاده از اون در پروژه هامون بکنیم (امیدوارم :/// ) و کد تمیز تر و باحال تری بنویسیم.
در php 8.1 شاهد افزوده شدن Enum هستیم که قبلا وجود نداشت که در زبان های دیگه پیاده شده بود مثل جاوا ولی ما محروم از اون بودیم که به لطف تیم توسعه php الان میتونیم به راحتی ازش استفاده کنیم و واقعا کاربردیه
بیایین یه مثال ازش ببینیم
<?php /** * Declare an enumeration. * It can also contain an optional 'string' or 'int' value. This is called backed Enum. * Backed enums (if used) should match the following criteria: * - Declare the scalar type, whether string or int, in the Enum declaration. * - All cases have values. * - All cases contain the same scalar type, whether string or int. * - Each case has a unique value. */ enum UserRole: string { case ADMIN = '1'; case GUEST = '2'; case WRITER = '3'; case EDITOR = '4'; } /** * You can access a case by using * the '::' scope resolution operator. * And, to get the name of the enum case, you * can use the '->' followed by the attribute 'name'. */ echo UserRole::WRITER->name; /** * To get the value of the enum case, you can * use the '->' followed by the attribute 'value'. */ echo UserRole::WRITER->value; ?>
همون طور که میبینید سینتکس ساده و تمیزی داره که میتونیم طبق مثال بالا ازش استفاده کنیم.
یکی از کاربرد های جالبش در فریمورک لاراول هست که میتونیم در validation یا در قسمت casts مدل هامون استفاده کنیم و با آخرین نسخه لاراول که تا امروز منتشر شده سازگار هست.
یکی دیگه از امکاناتی که اضافه شده امکان استفاده از Fibers هست که یه کامپوننت سطح پایینه که بهمون اجازه میده کد هایی بنویسیم که همزمان یا concurrent اجرا بشن.
به عنوان تعریف میتونیم بگیم که Fiber یه بلاکی از کد هست که استک مخصوص خودش رو داره (متغییر ها و ...) و جدا از برنامه اصلی اجرا میشه. این کامپوننت ها رو میتونیم به عنوان رگه ها یا انشعاباتی از اپ اصلی در نظر بگیریم و از داخل برنامه خودمون اجراشون کنیم.
وقتی که شروع شد کد اصلی نمیتونه اون رو تعلیق (suspend) یا حذف (terminate) کنیم فقط از داخل خود Fiber میشه اونو تعلیق یا متوقف کرد. وقتی Fiber به حالت تعلیق در میاد کنترل به برنامه اصلی بر میگرده و میتونیم Fiber رو از قسمتی که متوقف شده ادامه بدیم.
حالا بیایین یه مثال از Fiber ببینیم:
<?php /** * Initialize the Fiber. */ $fiber = new Fiber(function(): void { /** * Print some message from inside the Fiber. * Before the Fiber gets suspended. */ echo "Welcome to Fiber!\n" /** * Suspend the Fiber. */ Fiber::suspend(); /** * Print some message from inside the Fiber. * After the Fiber gets resumed. */ echo "Welcome back to Fiber!\n" }); /** * Print a message before starting a Fiber. */ echo "Starting a Fiber\n" /** * Start the Fiber. */ $fiber->start(); /** * Fiber has been suspened from the inside. * Print some message, and then resume the Fiber. */ echo "Fiber has been suspended\n" echo "Resuming the Fiber\n" /** * Resume the Fiber. */ $fiber->resume(); /** * End of the example. */ echo "Fiber completed execution\n" ?>
البته زیاد به کار ما نمیاد ولی خدا میدونه چه چیزهای جالبی از این ویژگی در فریمورک ها شاهد خواهیم بود من که هیجان دارم شما رو نمیدونم.
ویژگی دیگه ای که PHP 8.1 اضافه میکنه نوع بازگشتی never هست که به معنای هرگز هست. این نوع رو میتونیم در توابع و متد هایی به کار ببریم که برنامه رو متوقف خواهند کرد که میتونیم با Throw Execption یا die یا exit این کار رو انجام بدیم.
تفاوتی که نوع never با void داره تنها در اینه که void نشون میده برنامه بعد اجرای قطعه کد اجرا خواهد شد ولی never اینظوری نیست و بعد از اجرای کد های داخل متد یا فانکشن برنامه متوقف خواهد شد.
حالا بیایین یه قطعه کد ازش ببینیم
<?php /** * Route Class */ class Route { /** * Constructor of the class * @return void */ public function __construct() { } /** * Redirect To a Page * This function redirects to an URL specified by the user. * @method redirect() * @param string $url * @param integer $httpCode * @author Tara Prasad Routray <someemailaddress@example.com> * @access public * @return never */ public static function redirect($url, $httpCode = 301): never { /** * Redirect to the URL specified. */ header("Location: {$url}", true, $httpCode); die; } } Route::redirect('https://www.google.com'); ?>
در توضیح مثال بگم که وقتی متد redirect رو صدا میزنیم و اون اجرا میشه تا میرسه به تابع header که ازش خواستیم که ما رو ریدایرکت کنه به یه صفحه دیگه و بعدش میبینیم که از die استفاده کردیم که برنامه رو متوقف میکنه (یه نکته ای هم که هست بعضا فرض میشه که بعد تابع header که ریدایرکت میکنه بقیه کد اجرا نمیشه ولی کد های بعد تابع header اجرا میشه).
یه فیچر جدید دیگه که در PHP 8.1 اضافه شده کیورد readonly هست که میتونیم در هنگام تعریف پراپرتی های کلاس ازش استفاده کنیم و طبق اسمش هر پراپرتی که اینطوری تعریف بشه فقط یکبار میتونه مقدار بگیره و عیرقابل تغیر خواهد بود و اگه بخواهیم که اونو تغییر بدیم به ارور میخوریم.
حالا بیایین یه مثال ازش ببینیم:
<?php /** * User Class */ class User { /** * Declare a variable with readonly property. * @var $authUserID * @access public */ public readonly int $authUserID; /** * Constructor of the class. * @param integer $userID * @return void */ public function __construct($userID) { /** * Change the value of the property as specified. * Updating the value of readonly properties are * allowed only through the constructor. */ $this->authUserID = $userID; } /** * Update Auth User ID * This function tries to update the readonly property (which is not allowed). * @method updateAuthUserID() * @param integer $userID * @author Tara Prasad Routray <someemailaddress@example.com> * @access public * @return void */ public function updateAuthUserID($userID) { /** * Change the value of the property as specified. * Executing this function will throw the following error; * PHP Fatal error: Uncaught Error: Cannot modify readonly property User::$authUserID */ $this->authUserID = $userID; } } /** * Initialize the class and update the value of the readonly property. */ $user = new User(30); /** * Print the readonly property value. * This will print 30. */ echo $user->authUserID; /** * Call another function inside the class and try to update the class property. */ $user->updateAuthUserID(50); /** * Print the readonly property value. */ echo $user->authUserID; ?>
مقدار پراپرتی های readonly فقط و فقط داخل constrcutor کلاس قابل تغییر و مقداردهی هست.
یه فیچر جدید دیگه که در PHP 8.1 اضافه شده فلگ final برای ثابت های کلاس هست که این نوع ثابت ها غیرقابل تغییر خواهند بود حتی با استفاده از وراثت که به این معنی هست که این نوع ثابت ها نمیتونن توسط کلاس های فرزند به ارث برده شده و ovveride بشن.
این فلگ رو نمیتونیم با private باهم استفاده کنیم چون که بیرون از کلاس در دسترس نیستند و اگر هردو رو باهم استفاده کنیم منجر به ارور fatal می شود.
یه مثال ازش ببینیم و کاربردشو متوجه بشیم
<?php /** * UserRole Class */ class UserRole { /** * Declare a final class constant with a value. */ final public const ADMIN = '1'; } /** * User Class extending the UserRole Class */ class User extends UserRole { /** * Declare another constant with the same name * as of the parent class to override the value. * * Note: Overriding the value will throw the following error: * PHP Fatal error: User::ADMIN cannot override final constant UserRole::ADMIN */ public const ADMIN = '2'; } ?>
همون طور که میدونیم این کد با ارور مواجه خواهد شد.
یه فیچر جدید دیگه که در PHP 8.1 اضافه شده این تابع هست که برای مشخص کردن این که آرایه یک لیست منظم هست(شروع از 0) استفاده میشه.
زمانی true بازگشت میده که آرایه ایندکس هاش از 0 شروع بشه و عدد باشن و بینشون فاصله عددی نباشه و برای آرایه خالی هم true بازگشت میده.
بیاین یه مثال ببینیم تا بهتر متوجه بشیم
<?php /** * Returns true for empty array. */ array_is_list([]); /** * Returns true for sequential set of keys. */ array_is_list([1, 2, 3]); /** * Returns true as the first key is zero, and keys are in sequential order. * It is same as [0 => 'apple', 1 => 2, 2 => 3] */ array_is_list(['apple', 2, 3]); /** * Returns true as the first key is zero, and keys are in sequential order. * It is same as [0 => 'apple', 1 => 'scissor'] */ array_is_list(['apple', 'orange']); /** * Returns true as the first key is zero, and keys are in sequential order. * It is same as [0 => 'apple', 1 => 'scissor'] */ array_is_list([0 => 'apple', 'orange']); /** * Returns true as the first key is zero, and keys are in sequential order. */ array_is_list([0 => 'rock', 1 => 'scissor']); ?>
این رو هم در نظر بگیرید که این دوتا آرایه برابر هستند
<?php $arr1 = [ 'apple', 'car' ]; $arr2 = [ 0 => 'apple', 1 => 'car' ];
و آرایه ای که ایندکس هاش عدد نباشن یا از صفر شروع نشن یا بین عدد ها فاضله باشه منجر به false میشه.
<?php /** * Returns false as the first key does not start from zero. */ array_is_list([1 => 'apple', 'orange']); /** * Returns false as the first key does not start from zero. */ array_is_list([1 => 'apple', 0 => 'orange']); /** * Returns false as all keys are not integer. */ array_is_list([0 => 'apple', 'fruit' => 'orange']); /** * Returns false as the keys are not in sequential order. */ array_is_list([0 => 'apple', 2 => 'orange']); ?>
یکی دیگه از فیچر های این نسخه از PHP این توابع جدید هستند که کار با فایل رو آسونتر میکنن و شباهت هایی به تابع fflush داره که تمام buffered output رو به فایلی که open هست مینویسه. در صورتی که این دو تابع بر روی حافظه فیزیکی مینویسند.
تابع fsync یک نشانی حافظه دریافت کرده و سعی میکنه تغیرات رو در اونجا روی دیسک ذخیره کنه و بسته به موفقیت true یا false بر میگردونه و تابع fdatasync نیز به همین صورت عمل میکنه ولی به دلایلی سریع تر هست که خارج از حوصله هست.
یک مثال از این توابع جدید ببینیم:
<?php /** * Declare a variable and assign a filename. */ $fileName = 'notes.txt'; /** * Create the file with read and write permission. */ $file = fopen($fileName, 'w+'); /** * Add some text into the file. */ fwrite($file, 'Paragraph 1'); /** * Add a line break into the file. */ fwrite($file, "\r\n"); /** * Add some more text into the file. */ fwrite($file, 'Paragraph 2'); /** * You can use both the fsync() or fdatasync() functions * to commit changs to disk. */ fsync($file); // or fdatasync($file). /** * Close the open file pointer. */ fclose($file); ?>
همونطور که میبینین یک فایل رو ایجاد و تغییرش میدیم و سپس روی حافظه ذخیره میکنیم با توابع مذکور.
یکی از چیزهایی که تو زبان جاوا اسکریپت خیلی دوست دارم spread operator یا همون سه نقطه معروف هست که قبلا به صورت ناقص در PHP پیاده شده بود و برای آرایه های با ایندکس عددی کار می کرد فقط ولی در PHP 8.1 این مشکل برطرف شده و میتونیم ازش استفاده کنیم
بیاین یه مثال راجبش ببینیم که به چه صورت هست
<?php /** * Declare an array */ $fruits1 = ['Jonathan Apples', 'Sapote']; /** * Declare another array */ $fruits2 = ['Pomelo', 'Jackfruit']; /** * Merge above two arrays using array unpacking. */ $unpackedFruits = [...$fruits1, ...$fruits2, ...['Red Delicious']]; /** * Print the above unpacked array. * This will print: * array(5) { * [0]=> * string(15) "Jonathan Apples" * [1]=> * string(6) "Sapote" * [2]=> * string(6) "Pomelo" * [3]=> * string(9) "Jackfruit" * [4]=> * string(13) "Red Delicious" * } */ var_dump($unpackedFruits); ?>
یه فیچر دیگه که به PHP 8.1 اضافه شده این اندیس جدید هست که به متغییر گلوبال $_FILES اضافه شده که قبل از این نسخه امکان دریافت مسیر به همراه پوشه های آن فراهم نبود که از این رو نمیتونستیم یه پوشه کامل رو با استفاده از HTML آپلود کنیم ولی با این امکان میتونیم فایل رو در سرور با نام پوشه خودش در فولدر مشخص ذخیره کنیم. خلاصه میتونیم یه پوشه رو با فایلاش آپلود کنیم.
بیاین یه مثال ببینیم ازش:
<?php /** * Check if the user has submitted the form. */ if ($_SERVER['REQUEST_METHOD'] === 'POST') { /** * Print the $_FILES global variable. This will display the following: * array(1) { * ["myfiles"]=> array(6) { * ["name"]=> array(2) { * [0]=> string(9) "image.png" * [1]=> string(9) "image.png" * } * ["full_path"]=> array(2) { * [0]=> string(25) "folder1/folder2/image.png" * [1]=> string(25) "folder3/folder4/image.png" * } * ["tmp_name"]=> array(2) { * [0]=> string(14) "/tmp/phpV1J3EM" * [1]=> string(14) "/tmp/phpzBmAkT" * } * // ... + error, type, size * } * } */ var_dump($_FILES); } ?> <form action="" method="POST" enctype="multipart/form-data"> <input name="myfiles[]" type="file" webkitdirectory multiple /> <button type="submit">Submit</button> </form>
قبل از PHP 8.1 برای ایجاد تاریخ و زمان محلی فقط میتونستیم از IntlDateFormatter
استفاده کنیم.
که 8 فرمت از پیش تعریف شده دیروز (yesterday) ٬ امروز (today) و فردا (tomorrow) استفاده می کرد. ولی این فرمت ها به اندازه فرمت هایی که کلاس جدید فراهم میکند قابل شخصی سازی نیستند. این کلاس به ما اجازه میده فرمت رو بر اساس تاریخ , ماه یا زمان مشخص کنیم و کلاس کارش رو به خوبی انجام میده.
بیایم یه مثال ازش ببینیم تا کاربردشو ببینیم و خوب متوجه بشیم:
<?php /** * Define a default date format. */ $skeleton = "YYYY-MM-dd" /** * Parse a time string (for today) according to a specified format. */ $today = \DateTimeImmutable::createFromFormat('Y-m-d', date('Y-m-d')); /** * =========================== * PRINTING DATE IN USA FORMAT * =========================== * Initiate an instance for the IntlDatePatternGenerator class * and provide the locale information. * In the below example, I've used locale: en_US. */ $intlDatePatternGenerator = new \IntlDatePatternGenerator("en_US"); /** * Get the correct date format for the locale: en_US. * Following function "getBestPattern" will return: * MM/dd/YYYY */ $enUSDatePattern = $intlDatePatternGenerator->getBestPattern($skeleton); /** * Use the "formatObject" function of IntlDateFormatter to print as per specified pattern. * This will print the following: * Date in en-US: 12/03/2021 */ echo "Date in en-US: ". \IntlDateFormatter::formatObject($today, $enUSDatePattern, "en_US"). "\n" /** * ============================= * PRINTING DATE IN INDIA FORMAT * ============================= * Initiate an instance for the IntlDatePatternGenerator class * and provide the locale information. * In the below example, I've used locale: en_IN. */ $intlDatePatternGenerator = new \IntlDatePatternGenerator("en_IN"); /** * Get the correct date format for the locale: en_IN. * Following function "getBestPattern" will return: * dd/MM/YYYY */ $enINDatePattern = $intlDatePatternGenerator->getBestPattern($skeleton); /** * Use the "formatObject" function of IntlDateFormatter to print as per specified pattern. * This will print the following: * Date in en-IN: 03/12/2021 */ echo "Date in en-IN: ". \IntlDateFormatter::formatObject($today, $enINDatePattern, "en_IN"). "\n" ?>
تغیرات نسخه جدید PHP واقعا خوبه شاید بعضیاشون مستقیم به کار ما برنامه نویس هایی که معمولا از فریمورک ها استفاده میکنیم نیاد ولی انتظار میره که امکانات جالبی به فریمورک ها اضافه بشه و امیدوارم که بتونیم هرچه زود تر از این فیچر ها استفاده بکنیم با توجه به اینکه نسخه 7.4 هم به زودی از پشتیبانی خارج میشه.
اگه از مقاله خوشتون اومد یه قلب رو دریغ نکنید :)
خسته نباشیددددد :)))))))