خانه توسعهدهنده تکنولوژی بکاند پی اچ پی تغییرات PHP 8.0
تغییرات PHP 8.0
PHP 8.0 یک نسخه با تغییرات عمده و یک نقطه عطف قابلتوجه در PHP است، زیرا چندین ویژگی جدید برای تایپ سیستم، سینتکس، مدیریت خطا، رشتهها، برنامهنویسی شیءگرا و… ارائه کرده است.
PHP سعی میکند در مورد تغییرات backward incompatible که میتواند بخشهای زیادی از برنامهها را با مشکل مواجه کند، محافظهکار باشد و با این وجود، چندین ویژگی اساسی جدید را در PHP 8.0 ایجاد کرده است.
ویژگیهایی مانند Named Parameters ،JIT ،Attributes و Constructor Properties اصلاحات و تغییرات نحوی (syntax) اساسی را به ارمغان آوردهاند، در حالی که اصلاحاتی جزئی مانند مهاجرت resource به شیء، بهبودهای مدیریت خطا و تغییرات و بهبودهای عملگرها و عملگرهای مقایسهای احتمال باگهای نادیدهگرفتهشده را کاهش میدهند.
فهرست مطالب
TogglePHP 8.0 در چه زمانی منتشر شد؟
پیاچپی ۸ در تاریخ ۲۶ نوامبر ۲۰۲۰ به عنوان نسخهی جدیدی از این زبان به شکل رسمی در دسترس عموم قرار گرفت. این بهروزرسانی، بسیاری از بهینهسازیها و ویژگیهای قدرتمند را به زبان اضافه کرده است. در این مقاله از کوئرا بلاگ به مهمترین ویژگیهای این نسخه میپردازیم و مزیتهای آن نسبت به نسخههای قبل را بررسی میکنیم.
شاید به این مقاله هم علاقهمند باشید: PHP چیست؟
ویژگیهای جدید اصلی
Named Parameters
PHP 8.0 علاوهبر پارامترهای موقعیتی که از قبل وجود داشتند، پارامترهای نامگذاریشده را نیز در فراخوانی تابع امکانپذیر میکند.
str_contains(needle: 'Bar', haystack: 'Foobar');
این تغییر باعث میشود تا نامهای پارامتر تابع، بخشی از API عمومی باشند.
Attributes
attributeها به شما این امکان را میدهند که متادیتاها را برای توابع، کلاسها، پراپرتیها و پارامترها تعریف کنید. attributeها به نام کلاسهای PHP (که خود با یک attribute معرفی میشوند) مرتبط میشوند و با استفاده از Reflection API میتوان آنها را در زمان اجرا دریافت کرد.
#[CustomAttribute]
class Foo {
#[AnotherAttribute(42)]
public function bar(): void {}
}
attributeها امکان تعریف annotationهایی که قبلاً برای ذخیرهسازی آنها به DocBlock نیاز بود را بسیار آسان میکنند.
Constructor Properties
یک سینتکس جدید برای تعریف مستقیم پراپرتیهای کلاس از کانستراکتور کلاس (متد جادویی construct__
) اضافه شده است.
class User {
public function __construct(private string $name) {}
}
PHP 8.0 در constructor از تعریف سطح دسترسی (public
،private
یا protected
) و type hint پشتیبانی میکند. این پراپرتیها بهعنوان پراپرتیهای کلاس با همان سطح دسترسی و نوعی که در کانستراکتور معرفی میشوند، اضافه میشوند.
این قابلیت backward incompatible میتواند هنگام تعریف کلاسهای value-object، به کاهش boilerplate code کمک کند.
کامپایلر Just-In-Time
PHP Opcache از JIT پشتیبانی میکند. JIT بهطور پیشفرض غیرفعال است. درصورت فعالسازی آن، دستورالعملهای native را کامپایل و ذخیره میکند. JIT تفاوت محسوسی در برنامههای وب متصل به IO ایجاد نمیکند، اما باعث افزایش عملکرد برنامههایی که از CPU زیاد استفاده میکنند، میشود.
# Enabling JIT in php.ini
opcache.enable=1
opcache.jit_buffer_size=100M
opcache.jit=tracing
توجه داشته باشید که JIT هنوز جدید است و یک روز قبل از انتشار PHP 8.0 رفعاشکال شده است. لایههای اضافهشده توسط JIT دیباگ کردن و profiling را دشوارتر میکنند.
Null-safe Operator
یکی دیگر از تغییرات PHP 8.0، عملگر Null-safe است که ایمنی در زنجیرهسازی متد یا پراپرتی را هنگامی که امکان null
بودن مقدار برگشتی یا پراپرتی وجود دارد، فراهم میکند.
return $user->getAddress()?->getCountry()?->isoCode;
اگر عملگر ?->
null-safe با مقدار null
مواجه شود، بقیه عبارت را نادیده میگیرد و بلافاصله و بدون ایجاد خطا، null
را برمیگرداند.
match
expressions
match expressionها مشابه بلوکهای switch
هستند، با این تفاوت که بلوکهای match
مقایسههای type safe را فراهم میکنند، از یک مقدار بازگشتی پشتیبانی میکنند، برای خارج شدن به دستور break
نیاز ندارند و از چندین مقدار برای مطابقت پشتیبانی میکنند. همچنین با در نظر گرفتن همه موارد موجود برای مقایسه، تضمین میکنند که حداقل یکی از مطابقتها صورت میگیرد.
$response = match('test') {
'test' => $this->sendTestAlert(),
'send' => $this->sendNuclearAlert(),
};
ممکن است همه بلوکهای switch
بهخوبی به بلوکهای match
تبدیل نشوند، مخصوصاً در کدی که به backward compatibility یا بلوکهای switch
با چندین دستور (برخلاف عبارات تکخطی) احتیاج دارد.
WeakMapها
یک WeakMap اجازه ذخیرهسازی و مرتبط کردن مقادیر دلخواه را به keyهای شیء میدهد. اما بدون جلوگیری از garbage collect شدن، شیء با حذف شدن در هر جای دیگری از map خارج میشود.
یک WeakMap
مشابه SplObjectStorage است. هر دو از objects
بهعنوان کلید استفاده میکنند و اجازه ذخیره مقادیر دلخواه را میدهند. با این حال، یک WeakMap
مانع از بازیافت حافظه شیء نمیشود.
توابع و کلاسهای جدید
PHP 8.0 چند تابع جدید را برای سهولت بررسی رشته (بررسی وجود یک زیررشته در رشته، بررسی شروع رشته با یک زیررشته و بررسی خاتمه رشته با یک زیررشته) ارائه کرده است تا جایگزین فراخوانیهای strpos() !== false
ـــــــ که خوانایی کمتری دارند و بهدلیل عملگرهای مقایسهای weak type مستعد خطا هستند ـــــــــ شوند.
تابع | تعریف | مثال |
str_contains | بررسی میکند که آیا needle درون haystack میباشد یا خیر | str_contains('Foobar', 'Foo') |
str_starts_with | بررسی میکند که آیا needle با رشته haystack آغاز میشود یا خیر | str_starts_with('PHP 8.0', 'PHP') |
str_ends_with | بررسی میکند که آیا needle با رشته haystack پایان مییابد یا خیر | str_ends_with('PHP 8.0', '8.0') |
PHP 8.0 همچنین توابعی مانند fdiv ،get_resource_id ،get_debug_type و preg_last_error_msg را ارائه کرده است.
تابع | تعریف |
fdiv | بخش float از استاندارد IEEE-754 در Floating-Point Arithmetic |
get_resource_id | ID داخلی را برای PHP resource موردنظر برمیگرداند. |
get_debug_type | type داخلی یک متغیر را برمیگرداند. |
preg_last_error_msg | پیغام خطای آخرین عملیات preg را برمیگرداند. |
رابط جدید stringable
از دیگر تغییرات PHP 8.0 میتوان به رابط جدید Stringable
اشاره کرد؛ که بهطور خودکار به تمام کلاسهایی که روش tostring__
را پیادهسازی میکنند، اضافه میشود و آنها صریحاً اعلان implements Stringable
را نمایش میدهند.
با استفاده از رابط Stringable
، معرفی typeهای string|Stringable
به توابعی که میتوانند رشتهها یا اشیاء را با روش ()tostring__
بپذیرند یا رد کنند، بسیار آسان شده است.
کلاس جدید PhpToken
Tokenizer
کلاس جدید PhpToken
یک رابط شیءگرا را بهعنوان جایگزینی برای تابع مبتنی بر آرایهی token_get_all
فراهم میکند.
بیشتر بخوانید: آرایه های PHP به زبان ساده
بهبودهای Type System
PHP 8.0 با افزودن union typeها و تایپ mixed
، تایپ سیستم را بهبود بخشیده است.
Union Typeها
Union Typeها اجازه معرفی بیش از یک تایپ (return types ،parameters و class properties) را میدهند.
function parse_value(string|int|float): string|null {}
همچنین از false
بهعنوان type خاصی (برای Boolean false
) پشتیبانی میکنند؛ خصوصیتی رایج در کدهای قدیمی که از Exceptionها استفاده نمیکردند.
شبهتایپ mixed
جدید
PHP 8.0 تایپ mixed
را که قبلاً بهطور گسترده در کامنتهای DocBlock مورد استفاده قرار میگرفت، به همراه دارد.
function dd(mixed $var): void {
var_dump($var);
}
از تایپ mixed
میتوان برای نشان دادن اینکه هر تایپی میتواند پذیرفته یا برگردانده شود، استفاده کرد. در context کلاس/رابط، تایپ mixed
از قوانین اصل جایگزینی Liskov تبعیت میکند.
static
return type
این ویژگی که قبلاً در DocBlock پشتیبانی میشد، اکنون در PHP 8.0 پشتیبانی میشود. static
return type اعلام میکند که یک شیء از کلاس فراخوانیشده برگردانده خواهد شد.
class Foo {
public static function getInstance(): static {
return new static();
}
}
بهبودهای مدیریت خطا
یک تغییر عمده و backward incompatible در PHP این است که اکنون توابع داخلی با type errorها یا value errorها مخالفت میکنند.
این تغییر، رفتار قدیمی PHP در بروز یک هشدار و برگرداندن null
در صورت مواجه شدن با مقداری که نمیتواند استفاده کند را اصلاح میکند. این رفتار اغلب نامطلوب است، زیرا هشدارهای PHP اجرای بلوک باقیمانده را متوقف نمیکنند.
هشدارهای تابع داخلی TypeError
ها و ValueError
ها را نادیده میگیرند
تقریباً تمام توابع داخلی در PHP اکنون type checking را اعمال میکنند و بهجای هشدارها، PHP اکنون TypeErrorها یا ValueErrorها را نادیده میگیرد. براساس کدهای قدیمی، این تغییر میتواند مشکلاتی ایجاد کند. اکنون PHP با این خطاها جسورانهتر و غیرقابلبخشش برخورد میکند.
throw
در expressionها
قبل از PHP 8.0، امکان پرتاب یک استثنا از یک expression (بهعنوان مثال یک ternary statement) وجود نداشت. امکانپذیر شدن این مورد نیز یکی دیگر از تغییرات PHP 8.0 است.
$value = isset($_GET['value'])
? $_GET['value']
: throw new \InvalidArgumentException('value not set');
Catch
exceptions فقط از طریق type
در PHP 8.0، میتوانیم exceptionها از طریق تایپ آنها و بدون گرفتن شیء exception دریافت کنیم.
try {
} catch (TypeError) {
// Did not catch the $exception object
}
error reporting پیشفرض روی E_ALL
تنظیم شده است
کانفیگ پیشفرض PHP 8.0 روی نمایش همه پیغامهای خطا است.با این کار تمام deprecationها و strict warningها در ورژنهای قبل پنهان میشوند.
startup errorها بهصورت پیشفرض نمایش داده میشوند
این نسخه از PHP بهصورت پیشفرض، startup errorها (failure to load dynamic extensions، invalid INI configurations و…) را نمایش میدهد.
assertionها بهصورت پیشفرض exception صادر میکنند
assertionها (()assert
) استثناهایی هنگام assertion failureها پرتاب میکنند. قبل از PHP 8.0، به یک پیکربندی صریح که بهطور پیشفرض غیرفعال بود، احتیاج بود.
عملگر Error Suppression @
خطاهای fatal را غیرفعال نمیکند
PHP 8.0 رفتار عملگر Error Suppression @
را که fatal errorهایی که منجر به خرابی اسکریپت میشوند را غیرفعال میکرد، اصلاح کرده است، زیرا عملگر @
از fatal errorها جلوگیری نمیکند، بلکه پیغامهای خطا را پنهان میکند.
مهاجرت منبع (resource) به شیء (object)
یکی از تلاشهای طولانیمدت در توسعه PHP کنار گذاشتن resource
تایپها بود، زیرا کار کردن با آنها دشوار بود. حتی در PHP 8.0 نیز resourceها از typing پشتیبانی نمیکنند.
resource
objectها با زبالهروب (garbage collector) نیز بهخوبی کار نمیکردند. این امر منجر به نشت حافظه (memory leak) در resource
objectهایی (مانند xml
) میشد.
در PHP 8.0، برخی از پرکاربردترین افزونهها از resource
objectهای متداول به کلاسهای استاندارد PHP منتقل شدهاند.
در resource object ،PHP 8.0ها بهعنوان value-objectها بهجای کلاسهای کاملاً مشخص با متدهای موجود در آنها کار میکنند. اکثر این کلاسها امکان ایجاد نمونهسازی با ساختار جدید ()Foo
را نیز ندارند و باید با توابع موجود که resource
objectها را در نسخههای قبلی بازگرداندهاند، نمونهسازی شوند.
مهاجرت resource
به شیء در PHP 8.0 کاملاً یکپارچه است، زیرا در همه توابع اشیاء جدید را برگردانده و میپذیرد و با همان معنای resource
objectهای قبلی رفتار میکند.
object (PHP >= 8.0) | resource (PHP < 8.0) | Extension |
CurlHandle | Curl | Curl |
CurlMultiHandle | curl_multi | Curl |
CurlShareHandle | curl_share | Curl |
GdImage | gd | GD |
Socket | Sockets | Sockets |
AddressInfo | AddressInfo | Sockets |
OpenSSLAsymmetricKey | OpenSSL key | OpenSSL |
OpenSSLCertificate | OpenSSL X.509 | OpenSSL |
OpenSSLCertificateSigningRequest | OpenSSL X.509 CSR | OpenSSL |
XMLWriter | xmlwriter | XMLWriter |
XMLParser | xml | XML |
تغییرات برنامهنویسی شیءگرا (object-oriented) در PHP
PHP 8.0 اولین نسخه با تغییرات عمده است که درمورد نقض اصل جایگزینی Liskov سختگیری میکند. نسخههای قبل از PHP 8.0 در نحوه مدیریت امضای ناسازگار متدها، مشکلاتی داشتند.
در PHP 8.0، همه عدمتطابق امضاها، از جمله traitهای انتزاعی، منجر به fatal error میشوند. علاوه بر این، امضاها برای متدهای جادویی PHP نیز اجرا میشوند.
Fatal errorها در امضاهای متد ناسازگار
در این نسخه، وقتی اصل جایگزینی Liskov هنگام ارثبری کلاسها یا پیادهسازی رابطها رعایت نشود، fatal errorهایی ایجاد میشوند. قبل از PHP 8.0، فقط امضاهای ناسازگار هشدار ارسال میکردند.
class Foo {
public function process(stdClass $item): array {}
}
class SuperFoo extends Foo{
public function process(array $items): array {}
// ^^^^^ mismatch
}
Fatal error: Declaration of SuperFoo::process(array $items): array must be compatible with Foo::process(stdClass $item): array in ... on line ...
امضاهای کلاس متد جادویی با سختگیری اجرا میشوند
از نسخه PHP 8.0 به بعد، اگر متدهای جادویی (بهعنوان مثال ()tostring__
و ()get__
و…) typeها را اعلام کنند، باید امضای موردانتظار PHP را پیادهسازی کنند. این تغییر بهمنظور جلوگیری از اعلام یک متد جادویی توسط کاربر که از معنای اصلی آن پیروی نمیکند، ایجاد شده است.
class Foo {
public function __toString(): object
{
}
}
در نسخههای قبلی PHP، تعاریفی مانند Foo::__toString(): object
مجاز بودند، اما در PHP 8.0 اگر امضا مطابق با الزامات نباشد، یک استثنا ارسال میشود.
فراخوانی استاتیک متدهای غیراستاتیک کلاس منجر به fatal error میشود
PHP 8.0 دیگر اجازه فراخوانی استاتیک متدهای غیراستاتیک کلاس را نمیدهد.
class Foo {
public function bar() {}
}
Foo::bar();
نسخههای قبلی اخطار deprecation منتشر میکردند، اما از PHP 8.0 به بعد یک fatal error ایجاد میشود.
قوانین وراثت (inheritance) در روشهای کلاس خصوصی اعمال نمیشوند
PHP 8.0 سختگیری در اجرای abstract
و static
را برای متدهای private
کلاس کم میکند. این تغییر بهدلیل اینکه متدهای private
فقط private
هستند، ایجاد شده است.
در PHP 8.0، کلاسهای فرزند (child class) مجاز به تعریف متدهای abstract
و تغییر flagهای static برای متدهای خصوصی هستند.
ثابت جادویی class::
روی اشیاء پشتیبانی میشود
ثابت جادویی class::
نام کلاس را بهصورت کامل برمیگرداند. در نسخههای قبل، این ثابت فقط در کلاسها (مانند Foo\Bar::class
) مجاز بود، اما در PHP 8.0، ثابت جادویی class::
روی اشیاء نمونهسازیشده نیز کار میکند.
تغییرات مرتبط با رشته
در بین تغییرات PHP 8.0، چندین تغییر ظریف وجود دارد که ممکن است در ابتدا مشخص نباشند، اما میتوانند نتایج کاملاً غیرمنتظرهای را به همراه داشته باشند.
یک تفاوت عمده در PHP 8.0 این است که PHP اکنون یک رشته خالی بین هر کاراکتر از یک رشته مشخص درنظر میگیرد.
قبل از PHP 8.0، بررسی وجود یک رشته خالی (""
) مجاز نبود، اما PHP 8.0 آن را میپذیرد و اینکه یک رشته خالی بین هر کاراکتر وجود دارد را برمیگرداند.
مدیریت چندبایتی یا توابعی مانند strlen
هنوز همان مقادیر نسخههای قدیمی را برمیگردانند، اما همه توابعی که یک زیررشته را در یک رشته جستجو میکنند، تغییر کردهاند.
علاوه بر این، PHP 8.0 نحوه اولویتبندی و پشتیبانی از اصلاحکنندههای جدید در توابع sprintf
(مانند اصلاحکنندگان %h
و %H
و *
width and precision) توسط عملگر الحاق رشته را تغییر داده است.
substr
،iconv_substr
و grapheme_substr
رشته خالی را در offsetهای خارج از محدوده برمیگردانند
این توابع پارامترهای needle و offset را به طول رشته مقید میکنند و بهجای برگرداندن false
، یک رشته خالی را برمیگردانند.
substr('FooBar', 42, 3); // "" in PHP >=8.0, false in PHP < 8.0
mb_substr('FooBar', 42, 3); // "" in PHP >=8.0, false in PHP < 8.0
iconv_substr('FooBar', 42, 3); // "" in PHP >=8.0, false in PHP < 8.0
grapheme_substr('FooBar', 42, 3); // "" in PHP >=8.0, false in PHP < 8.0
عملگرهای -
/+
هنگام استفاده با عملگر (.
)concat تقدم بیشتری دارند
هنگامی که عملگرهای ریاضی +
و -
در یک عبارت با عملگر الحاق (.
) استفاده شوند، تقدم بیشتری پیدا میکنند. این کار منجر به اخطار deprecation در نسخههای قبل از PHP 8.0 میشد، اما اکنون بیصدا و طبق warning اتفاق میافتد.
echo 35 + 7 . '.' . 0 + 5;
// 42.5 in PHP >= 8.0
// 47 in PHP <= 8.0
تبدیل مستقل محلی float
به string
هنگامی که یک مقدار float
به string
تبدیل میشود، PHP دیگر از زبان سیستم استفاده نمیکند. نسخههای قبل از PHP 8.0 هنگام انجام این کار، مکان فعلی (که thread-safe نیست) یا سیستم را درنظر میگرفتند که منجر به خروجیهای رشته ناسازگار میشد، زیرا برخی مناطق، به ویژه کشورهای اروپایی، جداکننده هزار و علامت اعشاری متفاوتی نسبت به ایالات متحده دارند.
برای تبدیل float
به string
، میتوان از اصلاح کننده f%
در توابعی نظیر printf
استفاده کرد.
علاوه بر این، اصلاحکنندههای جدید %h
و %H
برای توابعی نظیر printf
تعریف شدهاند که نسخههایی فارغ از زبان از اصلاحکنندههای %g
و %G
هستند.
بیشتر بخوانید: ویژگی های جدید PHP 8.3 که باید بشناسید – نگاهی کامل به تغییرات PHP 8.3
جمعبندی
در این مقاله تلاش کردیم تا به مهمترین تغییرات PHP 8.0 مانند Union Type، کامپایلر JIT، عملگر Null-safe و بسیاری دیگر بپردازیم؛ تا دید بهتری به ویژگیهای جدید این نسخه پیدا کنید. امیدواریم از خواندن این مقاله لذت برده باشید. خوشحال میشویم تا نظرات خود را در قالب کامنت با ما درمیان بگذارید.