رسول اسماعیلی
رسول اسماعیلی
خواندن ۸ دقیقه·۲ سال پیش

بررسی تغییرات PHP 8.1

حدود 20 روز پیش در تاریخ نهم جولای 2022 ورژن 8.1.8 زبان PHP منتشر شد و در این مقاله به بررسی تغییرات از نسخه 8.1 تا این نسخه می پردازم که میشه به قابلیت هایی مثل Enum ها که واقعا جاشون خیلی خالی بود یا کدنویسی Async که Fiber نام دارد و چندین قابلیت جدید دیگر اشاره کرد. ابتدا لیستی از تغییرات را تهیه کرده ام و در ادامه به توضیح و تحلیل آنها پرداخته ام.

لیست تغییرات:

  • Pure Intersection Types
  • Enums
  • The never Return Type
  • New readonly Properties
  • Final class constants
  • Fibers
  • New in initializers
  • First-Class Callable Syntax
  • Explicit Octal Numeral Notation
  • Array Unpacking Support for String-Keyed Arrays
  • New fsync() and fdatasync() Functions
  • New array_is_list() Function




Pure Intersection Types

  • اگر یادتون باشه در PHP 8 قابلیتی اضافه شد که نوع متغیرها یا خروجی و ورودی توابع را از چند نوع به صورت همزمان مشخص کنیم که با علامت پایپ از یکدیگر جدا میشدن.
class Number { public function __construct( private int|float $number) { } }

حالا تو این ورژن این قابلیت اضافه شده که بتونیم مشخص کنیم که یک متغیر باید از چند نوع باشه به صورت همزمان، لازمه که بگم برای استفاده از این قابلیت نوع داده هایی که مشخص می کنیم باید interface یا class باشه. به عبارت دیگه میتونیم اجبار کنیم که یک ورودی، خروجی یا یک متغیر حتما از یک یا چند کلاس و interface باشه.

مثال:

class A { private Traversable&Countable $countableI; public function setIterator(Traversable&Countable $countableI): void { $this->countableIterator = $countableIterator; } public function getIterator(): Traversable&Countable { return $this->countableI; } }

الان کلاس A یک property داره که حتما باید از نوع Traversable و Countable به صورت همزمان باشه، همچنین توابع getter و setter آن هم باید ورودی خروجی اشان از این دو نوع به صورت همزمان باشه.

یکم بیشتر توضیح بدم که برای دوستانی که متوجه نشدن شفاف تر بشه…ببینید نوع یک object از روی کلاس آن یا کلاس پدر یا Interface آن مشخص می شود. اگر از عملگر instanceof استفاده کنید برای اینکه تشخیص بدید که object مورد نظرتون از چه نوعی است و با هر کدوم از کلاس، کلاس والد یا Interface که پیاده سازی کرده مقایسه کنید جواب True خواهد بود.

حالا تو این ورژن میشه مشخص کرد که object ما از دو نوع همزمان باشد، مثلا از نوع کلاس Model باشد و همزمان AuthInterface را پیاده سازی کرده باشد.

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


Enums

قبلا که میخواستیم از enum ها در php استفاده کنیم یک کلاس تعریف می کردیم بعد enum های مورد نظرمون رو به صورت const تعریف میکردیم. کارمون رو راه می انداخت اما وقتی که قرار بود مقدار این enum ها از ورودی دریافت شود باید به صورت دستی بررسی میی کردیم که آیا مقدار درستی دارد یا نه.

class Status

{

const DRAFT = 'draft';

const PUBLISHED = 'published';

const ARCHIVED = 'archived';

}

function acceptStatus(string $status) {...}

حالا تو این ورژن enum ها به صورت کامل پشتیبانی می شوند:

enum Status

{

case Draft;

case Published;

case Archived;

}

function acceptStatus(Status $status) {...}

وقتی ورودی تابع را اجبار می کنیم که از نوع enum باشه در نتیجه حتما باید یکی از مقدار های enum را داشته باشه در غیر این صورت با ارور 500 مواجه خواهیم شد. ( :

The never Return Type

یک نوع جدید به خروجی توابع اضافه شده که اجبار میکنه اون تابع باید هیچ خروجی ضمنی و غیر ضمنی نداشته باشد و اجرای کد در آخر آن به پایان برسد و response به سمت کاربر بازگردد.

خروجی غیر ضمنی یعنی مثلا نمیتونه دستوری شبیه echo داشته باشه.

برای مثال:

function redirect(string $uri): never {

header('Location: ' . $uri);

exit();

}

Final class constants

وقتی که کلاسی دارای const بود و کلاس دیگری از آن ارث بری می کرد میتوانست const کلاس والد را overwrite کنه و دوباره آن را تعریف کنه، اما در این ورژن این امکان وجود دارد که const را به صورت final تعریف کنیم و جلوی overwirte شدن آن توسط کلاس فرزند را بگیریم.

در ورژن های گذشته:

class Foo

{

public const XX = "foo";

}

class Bar extends Foo

{

public const XX = "bar"; // No error

}

در این ورژن:

class Foo

{

final public const XX = "foo";

}

class Bar extends Foo

{

public const XX = "bar"; // Fatal error

}

Fiber

خب همونطور که میدونید ما در php همیشه به صورت sync کد زدیم و خود php این قابلیت رو نداشت که به صورت async کد بزنیم مگر اینکه از کتابخانه های موجود مثل amphp ،ReactPHP یا Guzzle برای این کار استفاده میکردیم.

در این نسخه این ویژگی با نام Fiber اضافه شده.

مثال:

$fiber = new Fiber(function (): void {

$value = Fiber::suspend('fiber');

echo "Value used to resume fiber: ", $value, "\n";

});

$value = $fiber->start();

echo "Value from fiber suspending: ", $value, "\n";

$fiber->resume('test');

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

وقتی از داخل تابع دستور suspend اجرا میشه روند اجرا متوقف می شود و تنها با تابع resume روی object آن میتوان ادامه کد داخل Fiber را اجرا کرد. ببینیم که فریم ورک ها و کتابخانه ها چه موارد جذابی را با استفاده از fiber پیاده سازی میکنند.

New in initializers

این امکان اضافه شده است که بتوان در Constructor کلاس ها object را ساخت و به عنوان مقدار پیش فرض ورودی constructor استفاده کرد.

class Service

{

private Logger $logger;

public function __construct(

Logger $logger = new NullLogger(),

) {

$this->logger = $logger;

}

}

New readonly Properties

این امکان فراهم شده است که در کلاس ها property هایی تعریف کنیم که بعد از این که اولین بار مقدار گرفتن دیگه تغییر نکنن.

class BlogData

{

public readonly Status $status;

public function __construct(Status $status)

{

$this->status = $status;

}

}

قبلا اگر میخواستیم این کارو انجام بدیم باید یک کلاس تعریف می کردیم و هممون اول یک property که private باشه رو مقدار دهی می کردیم و بعد فقط برای اون getter مینویشتیم:

class BlogData{ private Status $status;
public function __construct(Status $status)
{
$this->status = $status;
}
public function getStatus(): Status
{
return $this->status;
}

حالا اما این امکان وجود داره که به سادگی با کلمه readonly این کار رو انجام بدیم و حتی این property میتونه به صورت public هم باشه.

از مزیت هایی readonly اینکه گارانتی خیلی خوبی به برنامه نویس میده که مقداری که در ابتدا مقدار دهی کرده به هیچ عنوان تغییر نکرده است، حتی به اشتباه توسط برنامه نویس دیگری.

فقط موقع استفاده حواستون به دوتا نکته باشه که شاید از معایبش هم باشه، یکی اینکه موقع تعریف readonly حتما باید براش type تعریف کنید چون اگر تعریف نکنید به صورت پیشفرض null میشه و null هم نمیتونه readonly باشه و دومی اینکه اگر object را readonly تعریف میکنید در جریان باشید که خود object میتونه تغییر کنه ولی اون property که readonly تعریف کردیم همواره به حاوی همون object هست که در ابتدا مقدار دهی کردیم.

First-Class Callable Syntax

قابلیت جدیدی که اضافه کرده باعث میشه ما بتوانیم آسانتر closure function بنویسیم مثلا اگر قبلا میخواستیم توابع زیر را به متغیرها تخصیص بدیم که بعدا فراخوانشون کنیم باید اینطوری می نوشتیم:

$foo = [$this, 'foo']; $fn = Closure::fromCallable('strlen');

اما حال در این ورژن میتونیم این طوری بنویسیم:

$foo = $this->foo(...); $fn = strlen(...);

Explicit Octal Numeral Notation

شاید خیلی کم با اعدادی به غیر از مبنایی دهدهی مثل مبانی دو یا هشت و شانزده کار کرده باشیم، در ورژن های گذشته اعداد در مبنای هشت با نشانه صفر در ابتدای اعداد مشخص می شدند که در برخی موارد گیج کننده بود:

016 === 16; // false because `016` is octal for `14` and it's confusing 016 === 14; // true

حالا در این ورژن بعد از صفر باید یک حرف o هم اضافه کنیم که این گمراهی رو حل بکنه:

0o16 === 16; // false — not confusing with explicit notation 0o16 === 14; // true

Array Unpacking Support for String-Keyed Arrays

با تابع array_merge که آشنا هستید، حالا operator که در ورژن 7.4 معرفی شده است میتوان دو آرایه را merge کرد:

قبل از این ورژن:

$arrayA = ['a' => 1]; $arrayB = ['b' => 2]; $result = array_merge(['a' => 0], $arrayA, $arrayB); // ['a' => 1, 'b' => 2]

در این ورژن:

$arrayA = ['a' => 1]; $arrayB = ['b' => 2]; $result = ['a' => 0, ...$arrayA, ...$arrayB]; // ['a' => 1, 'b' => 2]

New fsync() and fdatasync() Functions

در این ورژن این دو تابع اضافه شده اند که البته این توابع از توابع های سیستم عامل لینوکس است که php از معدود زبان هایی بود که این توابع را پیاده سازی نکرده بود که بالاخره در این ورژن این اتفاق افتاد.

تابع fsync باعث میشه ما مطمئن شویم که وقتی داده ای را داخل فایلی ذخیره می کنیم به صورت کامل روی دیسک ذخیره شود و چیزی داخل بافر های php یا خود سیستم عامل باقی نماند و هنگام فراخوانی این توابع برنامه یا process دیگری به اون فایل دسترسی نخواهد داشت:

$doc = 'kinsta.txt'; $kin = fopen($doc, 'ki'); fwrite($kin, 'doc info'); fwrite($kin, &quot\r\n&quot); fwrite($kin, 'more info'); fsync($kin); fclose($kin);

تابع fdatasync همانند تابع fsync عمل میکند ولی مقداری سریعتر است و زمانی بهتر است از این تابع استفاده کنیم که metadata فایل برای ما ضروری نباشید و بیشتر روی محتوای فایل تمرکز داشته باشیم.

در واقع این دوتا تابع برای کسانی که برنامه های خود را بر پایه فایل می نویسند و خیلی با فایل سر و کار دارند کاربرد دارد.

New array_is_list() Function

این تابع هم در این ورژن معرفی شده است و بررسی میکند که آرایه شما از یک لیست تشکیل شده است یا خیر و مقدار true یا false را برمی گرداند. برای بیشتر شدن با این تابع به مثال های زیر دقت کنید:

// true array_is_list() examples array_is_list([]); // true array_is_list([1, 2, 3]); // true array_is_list(['cats', 2, 3]); // true array_is_list(['cats', 'dogs']); // true array_is_list([0 => 'cats', 'dogs']); // true array_is_list([0 => 'cats', 1 => 'dogs']); // true // false array_is_list() examples array_is_list([1 => 'cats', 'dogs']); // as first key isn't 0 array_is_list([1 => 'cats', 0 => 'dogs']); // keys are out of order array_is_list([0 => 'cats', 'bark' => 'dogs']); // non-integer keys array_is_list([0 => 'cats', 2 => 'dogs']); // gap in between keys

ممنون که تا انتهای این مقاله همراه من بودید، شادُ خندونُ سلامت باشید. (:

برنامه نویسسیستم عاملphp
رسول اسماعیلی - برنامه نویس
شاید از این پست‌ها خوشتان بیاید