ویژگی های جدید PHP8

ویژگی های جدید PHP8

نسخه 8 زبان PHP که یک نسخه اصلی می باشد قرار است در تاریخ 6 آذر منتشر شود. با توجه به اصلی بودن این نسخه، (برای اطلاعات بیشتر درمورد نسخه بندی ها دوره semantic versioning را مطالعه کنید.) قابلیت های جدید و بهبود های زیادی در بخش بهره وری (Performance) زبان را خواهیم داشت. در حال حاضر نسخه 8 در حالت feature freeze قرار دارد و به این معنی است که تا قبل از ریلیز این نسخه هیچ قابلیت جدیدی به آن اضافه نخواهد شد.

درصورتی که پروژه ی خود را به این نسخه بروز کنید احتمال اینکه کد شما برای کارکرد صحیح نیاز به تغییر داشته باشد زیاد است. البته درصورتی که شما از نسخه 7 و یا بالاتر PHP استفاده می کنید این تغییرات بسیار کم خواهند بود. در این مطلب لیستی از قابلیت های جدید این نسخه جمع آوری کرده ایم.

1-   Union Types

Union type ها مجموعه ای از چند نوع هستند که متغیر می تواند یکی از آنها را داشته باشد.

با توجه به اینکه نوع متغیر ها در PHP داینامیک است این قابلیت می تواند بسیار کاربردی باشد.

public function foo(Foo|Bar $input): int|float;

public function foo(Foo|null $foo): void;

توجه داشته باشید که void هرگز نمی تواند بخشی از union type باشد چرا که به این معنی است که تابع هیچ مقداری را بر نمی گرداند.

2-   عملگر nullsafe

اگر تا بحال از عملگر null coalescing استفاده کرده اید حتما با برخی محدودیت های آن از جمله اینکه نمی توان آن را هنگام صدا کردن متد ها استفاده کرد آشنا هستید.

$startDate = $booking->getStartDate();

$dateAsString = $startDate ? $startDate->asDateTimeString() : null;

 

با اضافه شدن این قابلیت جدید ما می توانیم کد بالا را به شکل زیر بنویسیم.

$dateAsString = $booking->getStartDate()?->asDateTimeString();

3-   آرگومان های نام گذاری شده

با استفاده از این قابلیت شما می توانید هنگام پاس دادن مقادیر به یک تابع، نام آن را مشخص کنید تا دیگر لازم نباشد ترتیب را رعایت کنید. همچنین می توانید پارامتر هایی که optional هستند و مقدار پیش فرض دارند را رد کنید.

function foo(string $a, string $b, ?string $c = null, ?string $d = null)
{ /* … */ }

foo(
    b: 'value b',
    a: 'value a',
    d: 'value d',
);

4-   عبارت match

این قابلیت مانند عبارت switch است با این تفاوت که عبارت match می تواند مقداری را برگرداند، (می توان نتیجه آن را داخل یک متغیر ریخت) به عبارت break نیازی ندارد، می تواند چند شرط را ترکیب کند و هنگام مقایسه به نوع متغیر ها اهمیت می دهد و نوع هیچ متغیری را به دیگری تبدیل نمی کند (به عنوان مثال 1 را به “1” تبدیل نمی کند).

$result = match($input) {
0 => "hello",
    '1', '2', '3' => "world",
};

 5-   تعریف property در متد constructor کلاس ها

به جای تعریف property در کلاس و نوشتن constructor برای آنها می توان این دو کار را ترکیب کرد. یعنی به جای نوشتن کد زیر:

class Money
{
    public Currency $currency;

    public int $amount;

    public function __construct(
        Currency $currency,
        int $amount,
    ) {
        $this->currency = $currency;
        $this->amount = $amount;
    }
}

از این به بعد می توان کد زیر را نوشت.

class Money
{
    public function __construct(
        public Currency $currency,
        public int $amount,
    ) {}
}

6-   نوع جدید مقادیر برگردانده شده در توابع

تا کنون فقط نوع self را می توانستیم برای خروجی توابع در نظر بگیریم و عبارت static به عنوان یک مقدار معتبر شناخته نمی شد، اما در نسخه جدید PHP از نوع static نیز می توان استفاده کرد.

class Foo
{
    public function test(): static
    {
        return new static();
    }
}

7-   نوع جدید mixed

احتمالا تا کنون عبارت mixed را در Doc comment های توابع و property ها دیده اید. از این به بعد می توانید mixed را به عنوان یک نوع (type) استفاده کنید.

نوع mixed به این معنی است که متغیر شما یکی از انواع زیر می باشد.

array و bool و callable و int و float و null و object و resource و string

توجه داشته باشید که نوع mixed  در ورودی توابع و property ها هم قابل استفاده است و تنها محدود به مقدار برگردانده شده توابع نیست. همچنین در نظر داشته باشید که نوع mixed به خودی خود null را شامل می شود و نمی توان آن را nullable کرد. بنابر این تکه کد زیر با خطا مواجه خواهد شد.

//خطا
function bar(): ?mixed {}

8-   تغییر throw از بیانیه به عبارت

در زبان های برنامه نویسی، عبارت (Expression)  مجموعه ای از مقادیر و توابع است که با یک دیگر ترکیب می شوند و توسط مفسر مقدار جدیدی را به وجود می آورند. در مقابل عبارت، بیانیه (Statement) وجود دارد که یک واحد قابل اجرا است و هیچ مقداری را به وجود نمی آورد. به بیان دیگر می توان گفت هدف عبارت ها ایجاد یک مقدار است درحالی که هدف بیانیه ها ایجاد تغییر در روند اجرای برنامه می باشد.
نمونه هایی از عبارت در زبان های برنامه نویسی شامل true, false, rand(),  2+4 و... می باشد و نمونه هایی از بیانیه در زبان های برنامه نویسی شامل if(), else{}, return, while(), try و... است.

در نسخه جدید، throw از بیانیه به عبارت تبدیل شده است و همین موضوع باعث می شود که بتوانیم از عبارت throw در جاهای بیشتری استفاده کنیم. مانند:

$triggerError = fn () => throw new MyError();

$foo = $bar['offset'] ?? throw new OffsetDoesNotExist('offset');

9-   رفع مشکلات ارث بری با متد های private

تا کنون بررسی هایی که روی متد های public و protected هنگام ارث بری انجام می شد روی متد های private هم انجام می گرفت. وجود این بررسی ها بی فایده است و در برخی مواقع به دلیل اینکه متد های private در کلاس فرزندان در دسترس نیستند، باعث ایجاد خطا در کد می شود. برخی از این خطا ها در مواقع زیر رخ می دهند:

· هنگامی که یک متد با متد private و final در کلاس پدر خود هم نام باشد.

· هنگامی که یک متد غیر static با متد private و static در پدر خود هم نام باشد یا بر عکس

· هنگامی که یک متد  abstract با متد private در کلاس پدر خود هم نام باشد.

در این بروزرسانی این مشکل برطرف شده است و دیگر هیچ بررسی مربوط به ارث بری برای متد های private انجام نمی شود. همچنین دیگر نمی توان یک متد private را به صورت final تعریف کرد و با انجام این کار یک خطا از نوع warning دریافت می کنیم.

Warning: Private methods cannot be final as they are never overridden by other classes

10-امکان استفاده از ::class روی اشیا

از این به بعد به جای استفاده از تابع get_class() روی اشیا جهت گرفتن نام کلاس آن ها می توانیم از class:: استفاده کنیم.

$foo = new Foo();

var_dump($foo::class);

11-catch کردن بدون تعریف متغیر

قبل از نسخه 8 هر زمان که شما می خواستید یک exception را در برنامه catch کنید مجبور به تعریف متغیر می شدید. اما در نسخه جدید می توانید مانند زیر عمل کنید.

try {
    // یک اتفاق بد رخ داد
} catch (MySpecialException) {
    Log::error("Something went wrong");
}

توجه داشته باشید که مشخص کردن نوع exception الزامی است و شما نمی توانید یک catch بدون ورودی بنویسید. برای catch کردن همه خطا های برنامه می توانید از نوع throwable استفاده کنید.

12- قرار دادن "," اضافه

تا کنون این کار در آرایه ها و ورودی توابع امکان پذیر بود. در نسخه جدید، شما می توانید هنگام تعریف توابع یا نوشتن بخش use برای closure ها نیز مانند زیر عمل کنید.

public function(
    string $parameterA,
    int $parameterB,
    Foo $objectfoo,
) {
    // …
}

13- نوع Stringable

از این به بعد Stringable می تواند به عنوان یک نوع در ورودی متد ها و... استفاده شود. هر زمان که کلاسی متد __toString را داشته باشد از این نوع محسوب می شود. همچنین کلاس هایی که از Interface با نام Stringable پیروی می کنند نیز از این نوع محسوب می شوند.

class Foo
{
    public function __toString(): string
    {
        return 'foo';
    }
}

function bar(string|Stringable $stringable) { /* … */ }

bar(new Foo());
bar('abc');

14-  تابع ()str_contains

تا قبل از نسخه جدید برای اینکه بدانیم یک رشته شامل رشته دیگری هست یا نه باید کد زیر را می نوشتیم.

if (strpos('string with lots of words', 'words') !== false) { /* … */ }

اما در نسخه جدید کافی است کد زیر را بنویسیم.

if (str_contains('string with lots of words', 'words')) { /* … */ }

15- دو تابع جدید ()str_starts_with و ()str_ends_with

برای اینکه بدانیم رشته ای با رشته ی دیگر آغاز می شود یا خیر می توانیم از تابع ()str_starts_with مانند زیر استفاده کنیم.

str_starts_with('haystack', 'hay'); // true

همچنین برای تشخیص این که یک رشته با رشته دیگر تمام می شود یا خیر نیز تابع str_ends_with() را صدا میزنیم.

str_ends_with('haystack', 'stack'); // true

 16- بهبود استفاده از متد های abstract در trait ها

در حال حاضر شما می توانید در trait های خود متد هایی را از نوع abstract تعریف کنید تا کلاسی که آنها را استفاده می کند مجبور  به پیاده سازی آن ها باشد. اما اکنون درستی امضای (signature)  آن ها بررسی نمی شود. به عنوان مثال اگر شما در trait مشخص کنید که خروجی یک متد abstract باید از نوع عددی باشد و کلاسی که آن را پیاده سازی می‌ کند نوع عددی را به عنوان نوع برگشتی از متد مشخص نکند، هیچ خطایی دریافت نمی کند. تکه کد زیر در حال حاضر خطایی ندارد.

trait Test {
    abstract public function test(int $input): int;
}

class UsesTrait
{
    use Test;

    public function test($input)
    {
        return $input;
    }
}

 اما در نسخه 8 امضای متد های abstract که توسط trait مجبور به پیاده سازی آن هستیم بررسی می شود. بنابراین کلاس UsesTrait در تکه کد بالا را باید به صورت زیر بنویسیم تا خطایی دریافت نکنیم.

class UsesTrait
{
    use Test;

    public function test(int $input): int
    {
        return $input;
    }
}

17- تغییر اولویت هنگام  concatenate کردن

اگر تا کنون کدی مانند زیر را می نوشتید.

echo "sum: " . $a + $b;

PHP آن را به شکل زیر تفسیر می کرد.

echo ("sum: " . $a) + $b;

نسخه هشت زبان PHP  آن را به شکل زیر تفسیر می کند.

echo "sum: " . ($a + $b);

18- بررسی سخت گیرانه تر نوع ها برای عملگر های حسابی و بیتی (bitwise)

تا قبل از نسخه هشت می توانستیم از عملگر های حسابی یا بیتی روی آرایه ها و اشیا استفاده کنیم. اما انجام اینکار دیگر ممکن نیست و با انجام آن php  خطایی با نام TypeError به ما می‌دهد.

[] % [42]; //throws TypeError

$object + 4; //throws TypeError

19- مقایسه بهتر عدد ها با رشته

تا کنون در زبان PHP موارد عجیبی هنگام مقایسه رشته با عدد وجود داشت که نتیجه true بر می گرداند. مانند:

0 == "sokan"

موارد دیگری از این قبیل وجود دارد که در نسخه جدید برطرف شده است.

جمع بندی

در این مطلب سعی شد مهم ترین و پرکاربرد ترین تغییراتی که در نسخه 8 زبان PHP وجود دارد را با مثالی انتزاعی مطرح کنیم. در این بروزرسانی قابلیتی به نام

JIT compiler - Just In Time compiler نیز اضافه شده است که آن را در مطلبی جداگانه توضیح خواهیم داد.

در صورتی که فکر می کنید قابلیتی از این نسخه نیاز به توضیح بیشتری دارد با ما در بخش نظرات درمیان بگذارید.

از بهترین نوشته‌های کاربران سکان آکادمی در سکان پلاس


online-support-icon