تغییرات جدید نسخه 8 زبان PHP چیست؟ (قسمت پایانی)

What's New in PHP 8? - Part 6

09 مرداد 1399
تغییرات جدید نسخه ی 8 زبان PHP چیست؟ (قسمت ششم و پایانی)

به جلسه ی ششم از ویژگی های جدید PHP 8 خوش آمده اید! در قسمت قبل با مفاهیم مهمی مانند GC یا garbage collection آشنا شدیم. در همان جلسه به صورت خلاصه مثالی زدم که اگر از کلاس مشخصی یک نمونه یا شیء ساخته باشیم این شیء در مموری خواهد بود و فضای مموری را اشغال می کند تا زمانی که دیگر به آن نیاز نداشته باشیم. اگر نیاز ما به این شیء برطرف شد، باید آن را از مموری دور بیندازیم تا فضای مموری را خالی کنیم در غیر این صورت مموری ما آنقدر اشغال می شود که دیگر جایی برای چیزی نیست. به این فرآیند بازگردانی مموری GC یا garbage collection می گویند که به نوعی در تمام زبان های برنامه نویسی پیاده سازی شده است. حالا نوبت بررسی موارد باقی مانده و ویژگی های جدید زبان PHP است.

استفاده از Trailing Comma در لیست پارامترها

Trailing comma ها ویرگول (comma) هایی هستند که به لیست هایی از آیتم های مختلف اضافه می شوند و بسته به زمینه ی استفاده شده، اجازه ی پیوست شدن موارد بیشتری را می دهند. به طور مثال در نسخه ی 7.2 زبان PHP قابلیت اضافه کردن Trailing comma به آرایه ها و namespace های گروهی اضافه شد. به مثال زیر توجه کنید:

<?php
$colors = [
  'blue',
  'red',
  'green',
];

اگر به عنصر آخر این آرایه نگاه کنید (green) یک ویرگول می بینید! شاید در ابتدا تصور کنید که این کد اشتباه است اما اینطور نیست! با اضافه کردن این ویرگول می توانیم با خیال راحت آرایه ها را با هم ادغام کنیم و دیگر نگران عنصر آخر و مشکلات آن نباشیم. سپس در نسخه ی 7.3 زبان PHP این قابلیت در صدا زدن توابع نیز مجاز شد. مثال:

<?php

array_merge(
  $greenColors,
  $redColors,
  $yellowColors,
);

حالا در نسخه ی 8 زبان PHP می توانیم از قابلیت trailing commas در لیست پارامترهای متدها و توابع و closure ها نیز استفاده کنیم! مثال:

class Foo {
	public function __construct(
		string $x,
		int $y,
		float $z, // trailing comma
	) {
		// do something
	}
}

این پیشنهاد با 58 رای موافق و 1 رای مخالف تایید شده است.

استفاده از نحو class:: روی اشیاء

می دانیم که برای دریافت نام یک کلاس می توانیم از نحو Foo\Bar::class استفاده کنیم اما یک RFC جدید پیشنهاد می دهد که بتوانیم همین نحو را به اشیاء نیز بسط بدهیم تا بتوانیم نام کلاسِ یک شیء را نیز پیدا کنیم. به کد زیر توجه کنید:

$object = new stdClass;
var_dump($object::class); // "stdClass"
 
$object = null;
var_dump($object::class); // TypeError

همانطور که می بینید ما از این نحو (syntax) روی اشیاء بالا استفاده کرده ایم. بنابراین در نسخه ی 8 زبان PHP استفاده از object::class$ برابر با استفاده از (get_class($object خواهد بود. همچنین اگر object$ یک شیء نباشد یک خطای TypeError به ما برگردانده می شود. این پیشنهاد بدون رای مخالف و با تمام آرا تصویب شد.

نسخه دوم attributes

ممکن است که با Attributes یا همان annotations در زبان های دیگر آشنا باشید. attributes نوعی از متادیتاهای ساختاریافته هستند که خصوصیات یک شیء یا عنصر یا فایل را مشخص می کنند. تا نسخه ی 7.4 زبان PHP تنها راه اضافه کردن متادیتا به کلاس ها و توابع و غیره استفاه از doc-comment یا همان Doc-block بود که در قسمت های قبلی به آن اشاره کرده بودیم. بگذارید برایتان مثالی بزنم. فرض کنید که می خواهیم این تابع را تعریف کنیم:

function add ($a, $b) {
    return $a + $b;
}

حالا می خواهیم برای آن متادیتا (metadata - در اصطلاح یعنی داده هایی در مورد داده های ما!) بگذاریم، یعنی به صورت کامنت برای کسی که از این تابع استفاده می کند توضیح بدهیم که چه کار باید انجام بدهد. تابع بالا بسیار ساده است و نیازی به متادیتا ندارد اما برای روشن شدن موضوع این کار را می کنیم:

/**
 * Enter description here...
 *
 * @param unknown_type $a
 * @param unknown_type $b
 * @return unknown
 */

همانطور که می بینید doc-comment ها کامنت هایی هستند که شبیه به documentation می باشند و نحوه ی استفاده را توضیح می دهند. در مثال بالا باید به جای Enter description here، توضیحی در مورد تابع بنویسید. سپس param@ ها نوع یا تایپ پارامترها را مشخص می کنند و در نهایت return@ مشخص می کند که تابع ما چه چیزی را برمی گرداند (رشته یا عدد یا غیره).

حالا یک RFC جدید ثبت شده است که به ما اجازه می دهد از attributes ها برای تعریف متادیتا در کلاس ها و توابع استفاده کنیم. این attribute ها باید قبل از تعریف تابع یا کلاس نوشته شوند. به مثال زیر از این RFC توجه کنید:

<<ExampleAttribute>>
class Foo
{
	<<ExampleAttribute>>
	public const FOO = 'foo';

	<<ExampleAttribute>>
	public $x;

	<<ExampleAttribute>>
	public function foo(<<ExampleAttribute>> $bar) { }
}

$object = new <<ExampleAttribute>> class () { };

<<ExampleAttribute>>
function f1() { }

$f2 = <<ExampleAttribute>> function () { };

$f3 = <<ExampleAttribute>> fn () => 1;

البته شما می توانیم این attribute ها را با doc-comment ها ترکیب کنید:

<<ExampleAttribute>>
/** docblock */
<<AnotherExampleAttribute>>
function foo() {}

هر declaration ای (تعریف تابع یا کلاس یا غیره) می تواند یک یا چند مقدار مربوط داشته باشد:

<<WithoutArgument>>
<<SingleArgument(0)>>
<<FewArguments('Hello', 'World')>>
function foo() {}

یک مثال دیگر بدین شکل است:

class ProductSubscriber
{
    <<ListensTo(ProductCreated::class)>>
    public function onProductCreated(ProductCreated $event) { /* … */ }

    <<ListensTo(ProductDeleted::class)>>
    public function onProductDeleted(ProductDeleted $event) { /* … */ }
}

ما درون این attribute نوشته ایم ListensTo (یعنی گوش کن به) ProductCreated::class تا توضیح دهیم که کار این متد چیست. نوشتن این attribute ها نحو یا syntax خاص خودش را دارد بنابراین برای کسب اطلاعات بیشتر به RFC مربوطه مراجعه کنید:

https://wiki.php.net/rfc/attributes_v2

معرفی توابع جدید

نسخه ی 8 زبان PHP توابع جدیدی را معرفی کرده است که من چند مورد را بررسی می کنم. در حال حاضر برای پیدا کردن یک رشته در رشته ای دیگر باید از توابعی مانند strstr و strpos استفاده کنیم اما استفاده از آن ها اصلا راحت و ساده نیست و برای تازه کاران دردسرساز می شود. به مثال زیر توجه کنید:

$mystring = 'Managed WordPress Hosting';
$findme = 'WordPress';
$pos = strpos($mystring, $findme);

if ($pos !== false) {
	echo "The string has been found";
} else {
	echo "String not found";
}

همانطور که می بینید نحوه ی پیدا کردن findme$ در myString$ اصلا ساده نیست. همچنین در مثال بالا از ==! استفاده کرده ایم که تایپ دو مقدار را نیز مقایسه می کند که خودش باعث می شود در صورت برابر بودن موقعیت findme$ با صفر خطا دریافت نکنیم. به همین خاطر است که فریم ورک های PHP معمولا توابع کمکی را برای این موضوع ارائه می دهند. حالا یک RFC جدید تابع str_contains را ارائه داده است که استفاده از آن بسیار ساده تر است:

str_contains ( string $haystack , string $needle ) : bool

کد بالا چک می کند که آیا needle درون haystack می باشد یا خیر و بر همین اساس true یا false برمی گرداند. بنابراین کد بالا را می توانیم به شکل زیر بنویسیم:

$mystring = 'Managed WordPress Hosting';
$findme   = 'WordPress';

if (str_contains($mystring, $findme)) {
	echo "The string has been found";
} else {
	echo "String not found";
}

در زمان نوشتن این مقاله RFC می گوید که str_contains نسبت به بزرگی و کوچکی حروف حساس است اما ممکن است این موضوع در آینده تغییر کند. این تابع با 43 رای موافق و 9 رای مخالف تصویب شده است.

همچنین دو تابع دیگر نیز داریم:

  • str_starts_with: بررسی می کند که آیا یک رشته با مقدار خاصی آغاز شده است.
  • str_ends_with: بررسی می کند که آیا یک رشته با مقدار خاصی تمام شده است.

مثال:

str_starts_with (string $haystack , string $needle) : bool
str_ends_with (string $haystack , string $needle) : bool

به نظرم هر دو تابع واضح هستند و نیازی به توضیح اضافه ندارند. واضح است که اگر needle از haystack بزرگتر باشد، نتیجه false می شود. در زمان نوشتن این مقاله هر دو تابع case-sensitive (حساس به بزرگی و کوچکی حروف) هستند.

تابع بعدی get_debug_type است که به تابع قدیمی gettype شباهت دارد اما get_debug_type تایپ یک متغیر را به همراه نام کلاس آن مشخص می کند. به این مثال از gettype توجه کنید:

$bar = [1,2,3];

if (!($bar instanceof Foo)) { 
	throw new TypeError('Expected ' . Foo::class . ', got ' . (is_object($bar) ? get_class($bar) : gettype($bar)));
}

ما باید از is_object استفاده کنیم تا مطمئن شویم مقدار ما یک کلاس است یا غیر از کلاس اما با get_debug_type می توان گفت:

if (!($bar instanceof Foo)) { 
	throw new TypeError('Expected ' . Foo::class . ' got ' . get_debug_type($bar));
}

تفاوت های این دو را در جدول زیر مشاهده می کنید:

مقدار مثالی نتیجه در تابع ()gettype نتیجه ر تابع ()get_debug_type
1 integer int
0.1 double float
true boolean bool
false boolean bool
null NULL null
"Roxo.ir" string string
[1,2,3] array array
کلاسی با نام Foo\Bar object Foo/Bar
یک کلاس anonymous object class@anonymous

امیدوارم به خوبی با قابلیت های اصلی PHP 8 آشنا شده باشید. قابلیت های جزئی دیگری نیز وجود دارد که من آن ها را ذکر نمی کنم اما می توانید خودتان آن ها را پیدا کنید.


سایر قسمت‌های این مبحث را در لینک‌های زیر مطالعه کنید:

تغییرات جدید نسخه 8 زبان PHP (قسمت اول)
تغییرات جدید نسخه 8 زبان PHP (قسمت دوم)
تغییرات جدید نسخه 8 زبان PHP (قسمت سوم)
تغییرات جدید نسخه 8 زبان PHP (قسمت چهارم)
تغییرات جدید نسخه 8 زبان PHP (قسمت پنجم)

نویسنده شوید

دیدگاه‌های شما

در این قسمت، به پرسش‌های تخصصی شما درباره‌ی محتوای مقاله پاسخ داده نمی‌شود. سوالات خود را اینجا بپرسید.