نگاهی به ویژگی‌‌های جدید php ۸

ترجمه و تالیف : فاطمه شیرزادفر
تاریخ انتشار : 22 مرداد 99
خواندن در 6 دقیقه
دسته بندی ها : پی اچ پی

Php۸ در تاریخ ۲۶ نوامبر سال ۲۰۲۰ منتشر می‌شود. این یکی از نسخه‌های جدید و عمده است، به این معنی که تغییرات بزرگ، ویژگی‌هایی جدید و همینطور بهبود عمل‌کرد را ارائه می‌دهد. Php ۸ هم‌اکنون به صورت فعال در حال توسعه است و انتظار می‌رود نسخه‌ی آلفای آن در ۱۸ ژوئن ۲۰۲۰ بیرون بیایید.

به دلیل تغییرات بزرگ، احتمال بیشتری وجود دارد که در کد خود تغییراتی ایجاد کنید تا در php ۸ اجرا شود. اگر شما خودتان را با آخرین آپدیت‌ها به روز نگه داشته باشید، ارتقا آن نباید برای شما کار خیلی سختی باشد، چراکه بسیاری از تغییرات بزرگ در نسخه‌های قبل ۷.* منسوخ شده بودند. و نگران نباشید لیستی از تمامی چیزهایی که منسوخ شده را در این مقاله برای شما ذکر می‌کنم.

علاوه بر تغییرات بزرگی که اعمال شده، php ۸ مجموعه خوبی از ویژگی‌های جدید مثل کامپایلر JIT ،union type‌ ها، attribute ها و … را برای شما به ارمغان می‌آورد.

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

با ویژگی‌های جدید PHP شروع می‌کنیم،‌ البته به یاد داشته باشید که روند توسعه PHP ۸ هنوز فعال است بنابراین این لیست با‌گذشت زمان رشد می‌کند.

Union type ها rfc

با توجه به dynamically typed که در php وجود دارند، موارد بسیار زیادی وجود دارد که union type ها می‌توانند مفید باشند. union type ها مجموعه‌ای از دو یا چند type یا نوع است که نشان می‌دهد یکی از این موارد می‌تواند قابل استفاده باشد.

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


توجه داشته باشید که void هرگز نمی‌تواند بخشی از یک union type باشد، زیرا "no return value at all" ( هیچ مقدار برگشتی وجود ندارد)‌ را نشان می‌دهد. به علاوه، nullable union ها می‌توانند با استفاده از |null ، یا با ? نوشته شوند.

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

public function bar(?Bar $bar): void;

JIT rfc

JIT – درست به موقع- وعده پیشرفت‌های قابل توجهی در زمینه بهبود عمل‌کرد داده، البته نه همیشه در قالب web request ها. هیچ معیار مشخص و دقیقی در این جهت انجام مشخص نشده اما مطمئناً آن‌ها به نتیجه خواهند رسید.

اگر می‌خواهید اطلاعات بیشتری را جع به JIT در PHP به دست آورید، می‌توانید این مقاله را مطالعه کنید.

Attribute هاrfc

Attribute ها،‌ که معمولاً به عنوان annotations یا حاشیه‌نویسی در زبان‌های دیگر شناخته می‌شوند، راهی برای افزودن متادیتا به کلاس‌ها، بدون نیاز به ترجمه parse)‌docblock) ها،‌ارائه می‌دهد.

در یک نگاه سریع ، مثالی از آنچه attribute ها از RFC، به نظر می‌رسند را مشاهده کنید:

use App\Attributes\ExampleAttribute;

<<ExampleAttribute>>
class Foo
{
    <<ExampleAttribute>>
    public const FOO = 'foo';
 
    <<ExampleAttribute>>
    public $x;
 
    <<ExampleAttribute>>
    public function foo(<<ExampleAttribute>> $bar) { }
}
<<Attribute>>
class ExampleAttribute
{
    public $value;
 
    public function __construct($value)
    {
        $this->value = $value;
    }
}

توجه داشته باشید که این base Attribute در RFC اصلی PhpAttribute نامیده می‌شد، ‌اما پس از آن با RFC دیگری تغییر کرد. اگر می‌خواهید شیرجه‌ی عمیقی به چگونگی کار کردن attribute ها و چگونگی ساختن آن‌ها توسط خودتان، بزنید؛ می‌توانید این مقاله را با عنوان attributes in depth  مطالعه کنید.

Constructor property promotionrfc

این RFC برای اضافه کردن syntactic sugar برای ایجاد value object ها یا data transfer object ها. به جای مشخص کردن class propertie ها و یک constructor برای آن‌ها، اکنون php می‌تواند آن‌ها را به یکی و باهم ترکیب کند.

به جای انجام این کار‌:

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,
    ) {}
}

در مورد property promotion چیزهای زیادی برای گفتن وجود دارد، می‌توانید در مورد آن‌ها این مقاله اختصاصی را مطالعه کنید.

staticreturn type جدید rfc

اگرچه امکان برگشت دادن self و static وجود داشت، اما تا قبل از php ۸ ،استاتیک یک return type معتبر نبود. با توجه به dynamically typed در php، این ویژگی برای بسیاری از توسعه‌دهندگان مفید خواهد بود.

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

mixed type جدید

برخی‌ها ممکن است آن را یک شر ضروری بنامند: mixed type باعث می‌شود بسیاری احساسات درهمی داشته باشند. استدلال بسیار خوبی برای بیان آن وجود دارد: یک missing type (‌نوع از دست رفته) می‌تواند به معنی چیزهای زیادی در php باشد:

  • یک فانکشن یا null برمی‌گرداند یا چیزی برنمی‌گرداند
  • ما منتظر یکی از several type ها (انواع مختلف)‌ هستیم.
  • ما منتظر نوعی(type) هستیم که نمی‌تواند type hinting در  php باشد.

به دلایل بالا، mixed type چیز خوبی برای اضافه شدن است.خود mixed به معنای یکی از انواع زیر است:

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

توجه داشته باشید که mixed می‌تواند به عنوان پارامتر یا property type هم استفاده شود، نه فقط به عنوان یک return type (نوع برگشتی).

همچنین توجه کنید که از آن‌جا که mixed قبلاً شامل null بوده، مجاز نیست که آن را nullable کنیم.

موارد زیر این خطا را ایجاد می‌کند:

// Fatal error: Mixed types cannot be nullable, null is already part of the mixed type.
function bar(): ?mixed {}

Throw expression rfc

این RFC موجب تغییر throw از statement بودن به expression بودن شده، که می‌شود throw exception در بسیاری از مکان‌های جدید امکان‌پذیر باشد:

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

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

Weak maps rfc

با استفاده از weakrefs RFC که در php ۷.۴ اضافه شده است، پیاده‌سازی WeakMap هم در php ۸ اضافه شده است. WeakMap ها به object ها بر‌می‌گردد، که مانع object هایی که garbage collected می‌شوند، نمی‌شود.

به عنوان مثال از ORM ها استفاده کنید، آن‌ها غالباً cache‌هایی را اجرا می‌کنند که برای بهبود عمل‌کرد روابط بین موجودیت‌ها، بهentity classe ها رجوع می‌کنند. این entity object ها نمی‌توانند garbage collecte شوند، و در این مدت این cache به آن‌ها رجوع می‌کند، حتی اگر حافظه cache تنها چیزی باشد که به آن‌ها رجوع ( referencing) کند.

اگر این لایه‌ی cache به جای آن از reference ها و mapهای ضعیف استفاده کند،‌ php این آبجکت‌ها را هنگامی که هیچ‌چیز دیگری به آن‌ها reference نمی‌کند، garbage collect می‌کند.

به‌خصوص در این مورد از ORM ها، که می‌تواند صدها چیز را مدیریت کند. weak map ها می‌توانند روشی بهتر resource friendly برای برخورد با این آبجکت‌ها ارائه دهند.

مثالی از RFC و اینکه weak map ها چگونه به نظر می‌رسند:

class Foo 
{
    private WeakMap $cache;
 
    public function getSomethingWithCaching(object $obj): object
    {
        return $this->cache[$obj]
           ??= $this->computeSomethingExpensive($obj);
    }
}

::class های مجاز بر آبجکت‌ها rfc

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

$foo = new Foo();

var_dump($foo::class);

Non-capturing catches rfc

قبل از PHP ۸ هر زمان که می‌خواستید یک exception را بگیرید، مجبور بودید بدون توجه به اینکه از آن متغییر استفاده کرده‌‌اید یا نه، آن را در یک متغییر ذخیره کنید. با استفاده از non-capturing catches، ‌می‌توانید متغییر را حذف کنید، بنابراین به جای این کار :

try {
    // Something goes wrong
} catch (MySpecialException $exception) {
    Log::error("Something went wrong");
}

می‌توانید این کار را انجام دهید:

try {
    // Something goes wrong
} catch (MySpecialException) {
    Log::error("Something went wrong");
}

توجه داشته باشید که لازم است همیشه نوع آن را مشخص کنید، و مجاز به گرفتن یک empty نیستید. اگر می‌خواهید همه‌ی exception ها و error ها بگیرید، می‌توانید از Throwable به عنوان نوع گیرنده استفاده کنید.

کاماهای انتهایی در پارامتر لیست‌های rfc

قبلاً در هنگام فراخوانی یک تابع امکان‌پذیر بود، و هنوز کاماهای انتهایی در پارامتر لیست‌ها فاقد پشتیبانی است. اکنون در php ۸ مجاز است، به این معنی که می‌توانید موارد زیر را انجام دهید:

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

آبجکت‌های DateTime از اینترفیس ایجاد کنید rfc

شما قبلاً می‌توانستید یک آبجکت  DateTime  از یک آبجکت DateTimeImmutable با استفاده از DateTime::createFromImmutable($immutableDateTime) ایجاد کنید، اما روش دیگر گمراه کننده و مشکل بود. با افزودن DateTime::createFromInterface() و DatetimeImmutable::createFromInterface() اکنون یک روش کلی برای تبدیل آبجکت‌های DateTime و DateTimeImmutable به یکدیگر وجود دارد.

DateTime::createFromInterface(DateTimeInterface $other);

DateTimeImmutable::createFromInterface(DateTimeInterface $other);

اینترفیس جدید Stringable 

اینترفیس Stringable می‌تواند برای type hint هر چیزی که یک رشته است یا با پیاده سازی __toString() استفاده شود. علاوه بر این هر گاه یک کلاس __toString() را اجرا کند، به طور خودکار اینترفیس را در پشت صحنه پیاده‌سازی می‌کند و نیازی به اجرای آن به صورت دستی نیست.

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

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

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

فانکشن جدید str_contains()  

برخی ممکن است بگویند مدت زمان زیادی است که این ویژگی آمده، ‌اما در نهایت ما دیگر نیازی به تکیه بر strpo ها برای اینکه بدانیم یک رشته شامل رشته‌ی دیگری است یا خیر، نداریم.

به جای انجام این کار :

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

حالا می‌توانید این کار را انجام دهید :

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

فانکشن‌های جدید str_starts_with() وstr_ends_with()

دو مورد دیگر که مدت طولانی است به تأخیر افتاده است، این دو فانکشن هستند که اکنون در هسته اضافه شده‌اند.

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

فانکشن جدید fdiv()

فانکشن جدید fdiv() عملکردی مشابه فانکشن‌های fmod() وintdiv() دارد،‌که تقسیم با ۰ را امکان‌پذیر می‌سازد. به جای error ها، بسته به موردی که هست INF، -INF یا NAN دریافت خواهید کرد.

فانکشن جدید get_debug_type()

get_debug_type() نوع متغییر را برمی‌گرداند و چیزی که gettype() شبیه به چیزی به نظر می‌رسد؟ get_debug_type() خروجی‌های مفیدتری برای آرایه‌ها، رشته‌ها،anonymous classe ها و آبجکت‌ها برمی‌گرداند.

به عنوان مثال، فراخوانی gettype() در یک کلاس \Foo\Bar باعث بازگشت یک آبجکت می‌شود.

لیست کاملی از تفات‌های بین get_debug_type() و gettype() را می‌توانید در RFC پیدا کنید.

فانکشن جدید get_resource_id()

Resource ها متغییرهای ویژه‌ای در php هستند که به external resource ها بر می‌گردد. یکی از نمونه‌های آن MySQL connection هستند و دیگری file handle است.

به هر یک از این resource ها یک آیدی اختصای می‌یابد، ‌اگر چه قبل از این تنها راه شناخت این آیدی، cast کردن resource به int بود.

$resourceId = (int) $resource;

php ۸ فانکش‌های get_resource_id() را اضافه می‌کند و این عملیات را واضح‌تر و امن‌تر (type-safe) می‌کند.

$resourceId = get_resource_id($resource);

Abstract متدها در بهبود ویژگی‌ها(Traits)

صفات(Traits) می‌توانند abstract متدها را که باید توسط کلاس‌هایی که از آن‌ها استفاده می‌کند تا اجرا شوند، مشخص کند. هر چند یک پیش‌بینی برای احتیاط وجود دارد: قبل از php ۸ امضای پیاده‌سازی این متدها تائید نشده بود. موارد زیر معتبر بود:

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

class UsesTrait
{
    use Test;

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

php۸ هنگام استفاده از یک صفت و اجرای abstract متدها، اعتبارسنجی متدهای مناسب را برای اجرا انجام می‌دهد. به این معنی که باید به جای آن، اینگونه بنویسید:

class UsesTrait
{
    use Test;

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

پیاده‌سازی آبجکت به وسیله token_get_all()

فانکشن token_get_all() یک آرایه از مقادیر را برمی‌گرداند. این RFC یک کلاس PhpToken را با متد PhpToken::getAll() اضافه می‌کند. این پیاده‌سازی یا آبجکت‌ها به ‌جای مقادیر ساده کار می‌کند؛ همچنین حافظه کمتری مصرف می‌کند و خواندن آن راحت‌تر است.

اصلاح سینتکس متغییر rfc

از RFC : تعدادی از ناسازگاری‌ها در سینتکس متغییرهای php توسط Uniform Variable Syntax RFC حل شده است. این RFC در نظر دارد تعداد کمی از مواردی را که مورد غفلت واقع شده‌اند را بررسی کند.

Type annotationهای فانکشن‌های داخلی rfc

بسیاری از افراد برای اضافه کردن type annotation های مناسب به تمام فانکشن‌های داخلی ، با جدیت شروع به کار کردند. این یک مسأله طولانی بود و سرانجام با کلیه‌ی تغییرات ایجاد شده در php در نسخه‌های قبلی قابل حل بود. این به این معنی است که فانکشن‌های داخلی و متدها type اطلاعات کاملی از type ها در  بازتاب دارند.

Ext-json همیشه در دسترس است rfc

پیش از این، امکان کامپایل php بدون JSON extension وجود داشت ولی این دیگر امکان‌پذیر نیست. از آن‌جا که JSON بسیار مورد استفاده قرار می‌گیرد، بهتر است توسعه‌دهندگان همیشه بتوانند به آن تکیه کنند، به جای اینکه ابتدا از بودن extension اطمینان حاصل کنند.

تغییرات بزرگ

همانطور که قبلاً ذکر شد: این یک آيدیت اساسی است بنابراین تغییرات زیاد و بزرگی به وجود خواهد آمد. بهترین کار این است که به لیست کامل تغییرات در داکیومنت UPGRADING نگاهی بیندازید.

بسیاری از این تغییرات بزرگ در نسخه‌های قبلی ۷.* کاهش پیدا کرده، بنابراین اگر شما در طول این سال‌ها به روز مانده‌اید، ارتقا آن به php ۸ خیلی سخت هم نیست.

خطاهای Consistent type

فانکشن‌های تعریف شده توسط کاربر در php، قبلاً TypeError ها را بیرون می‌انداختند(throw)، اما فانکشن‌های داخلی این کار را نمی‌کردند،‌ بلکه warning ها حذف می‌کردند و null برمی‌گرداندند. از php ۸ رفتار توابع داخلی سازگار شده است.

طبقه‌بندی مجدد هشدارهای موتور Reclassified engine warnings) rfc)

بسیاری از خطاهایی که قبلاً فقط باعث warningها یا notice ها می‌شدند، اکنون به error تبدیل شده‌اند. Warning های زیر تغییر کرده‌اند.

  • Undefined variable: از notice به Error exception تغییر کرده.
  • Undefined array index: از notice به warning تغییر پیدا کرده.
  • Division by zero: به جای warning به DivisionByZeroError exception تغییر کرده.
  • Attempt to increment/decrement property '%s' of non-object :  از warning به Error exception تغییر کرده.
  • Attempt to modify property '%s' of non-object: از warning به Error exception تغییر کرده.
  • Attempt to assign property '%s' of non-object: از warning به Error exception تغییر کرده.
  • Creating default object from empty value:از warning به Error exception تغییر کرده.
  • Trying to get property '%s' of non-object:از notice به warning تغییر پیدا کرده.
  • Undefined property: %s::$%s:از notice به warning تغییر پیدا کرده.
  • Cannot add element to the array as the next element is already occupied:از warning به Error exception تغییر کرده.
  • Cannot unset offset in a non-array variable:از warning به Error exception تغییر کرده.
  • Cannot use a scalar value as an array:از warning به Error exception تغییر کرده.
  • Only arrays and Traversables can be unpacked:از warning به TypeError exception تغییر کرده.
  • Invalid argument supplied for foreach():از warning به TypeError exception تغییر کرده.
  • Illegal offset type:از warning به TypeError exception تغییر کرده.
  • Illegal offset type in isset or empty:از warning به TypeError exception تغییر کرده.
  • Illegal offset type in unset:از warning به TypeError exception تغییر کرده.
  • Array to string conversion:از notice به warning تغییر پیدا کرده.
  • Resource ID#%d used as offset, casting to integer (%d):از notice به warning تغییر پیدا کرده.
  • String offset cast occurred:از notice به warning تغییر پیدا کرده.
  • Uninitialized string offset: %d:از notice به warning تغییر پیدا کرده.
  • Cannot assign an empty string to a string offset:از warning به Error exception تغییر کرده.
  • Supplied resource is not a valid stream resource:از warning به TypeError exception تغییر کرده.

اپراتور @ دیگر fatal error ها را خاموش نمی‌کند rfc

ممکن است این تغییر،‌ خطاهایی را که قبل از php ۸ پنهان شده‌اند را نشان دهد. حتماً روی سروهای production خود این display_errors=Off را تنظیم کنید.

سطح گزارش error پیش‌فرض rfc

اکنون  E_ALL به جای همه چیز به جز E_NOTICE و E_DEPRECATED است. این به این معنی است که بسیاری از خطاهایی که قبلاً در سکوت نادیده گرفته شده بودند الان ظاهر شوند، اگرچه احتمالاً این پیش از php ۸ هم وجود داشته.

حالت PDO error پیش‌فرض rfc

از RFC : حالت error پیش‌فرض فعلی برای PDO خاموش است. این به این معنی است که وقتی که SQL error رخ می‌دهد،‌ هیچ‌گونه error یا warning رخ نمی‌دهد،‌ مگر اینکه توسعه‌دهنده خودش explicit error خود را اجرا کند.

این RFC قطعا error پیش‌فرض را به PDO::ERRMODE_EXCEPTION در php ۸ تغییر خواهد داد.

اولویت جمع‌بندی rfc

اگر چه قبلاً در php ۷.۴ بد بود، ‌اما اکنون این تغییر اعمال می‌شود. اگر می‌خواهید چیزی مثل این را بنویسید:

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

php قبلاً اینگونه تفسیر می‌کرد :

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

php ۸ آن را به گونه‌ای تفسیر می‌کند که به صورت زیر باشد:

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

بررسی نوعی دقیق‌تر برای عملگرهای ریاضی و bitwise

قبل از php ۸، ممکن بود که عملگرهای ریاضی یا bitwise را روی آرایه‌ها، resource ها یا آبجکت‌ها اعمال کرد. این دیگر امکان‌پذیر نیست و یک TypeError برمی‌گرداند:

[] % [42];
$object + 4;

تغییرات Reflection method signature 

سه متد signature برای reflection class ها تغییر یافته‌اند :

ReflectionClass::newInstance($args);
ReflectionFunction::invoke($args);
ReflectionMethod::invoke($object, $args);

اکنون تبدیل شده‌اند به:

ReflectionClass::newInstance(...$args);
ReflectionFunction::invoke(...$args);
ReflectionMethod::invoke($object, ...$args);

راهنمای به روز رسانی مشخص می‌کند که اگر این کلاس‌ها گسترش دهید و هنوز هم می‌خواهید از php ۷ و ۸ پشتیبانی داشته باشید، signature های زیر مجاز است:

ReflectionClass::newInstance($arg = null, ...$args);
ReflectionFunction::invoke($arg = null, ...$args);
ReflectionMethod::invoke($object, $arg = null, ...$args);

منبع

گردآوری و تالیف فاطمه شیرزادفر
آفلاین
user-avatar

تجربه کلمه‌ای هست که همه برای توصیف اشتباهاتشون ازش استفاده میکنن، و من همیشه دنبال اشتباهات جدیدم! برنامه‌نویس هستم و لینوکس‌ دوست

دیدگاه‌ها و پرسش‌ها

برای ارسال نظر لازم است ابتدا وارد سایت شوید
در حال دریافت نظرات از سرور، لطفا منتظر بمانید