علیرضا هادی زاده

PHP 31 اردیبهشت 1405 15 دقیقه مطالعه

راهنمای جامع PHP از نسخه ۸.۰ تا ۸.۵ – تمام ویژگی‌ها با کد عملی

راهنمای کامل و عملی تمام نسخه‌های PHP 8 از ۸.۰ تا ۸.۵ – به همراه کدهای اجراشدنی، مثال‌های واقعی، جدول بهبود عملکرد و تغییرات نسخه‌ها

ع

علیرضا

توسعه‌دهنده Laravel و نویسنده این یادداشت

PHP 8.0 PHP 8.1 PHP 8.2 PHP 8.3 PHP 8.4 PHP 8.5 آموزش PHP ویژگی‌های جدید PHP

راهنمای جامع PHP از نسخه ۸.۰ تا ۸.۵ – تمام ویژگی‌ها با کد عملی

از زمان انتشار PHP 8.0، این زبان جهشی بلند به سوی مدرن‌شدن، ایمنی بیشتر و کارایی بالاتر برداشته است.
هر نسخه از ۸.۰ تا ۸.۵ ویژگی‌هایی بنیادین اضافه کرده که شیوه کدنویسی PHP را برای همیشه تغییر داده‌اند: از Named Arguments و Match Expression گرفته تا Property Hooks و عملگر Pipe.
در این راهنما، همه ویژگی‌های کلیدی هر نسخه را با کدهای کامل، اجراشدنی و مقایسه قبل/بعد بررسی می‌کنیم تا هم برای تازه‌واردان و هم برای مهاجرت‌دهندگان، مرجعی کامل و کاربردی باشد.


جدول مقایسه سریع نسخه‌ها

نسخه تاریخ انتشار ویژگی‌های شاخص بهبود عملکرد (Symfony Demo)
8.0 ۲۶ نوامبر ۲۰۲۰ Named Arguments, Match, Attributes, JIT -
8.1 ۲۵ نوامبر ۲۰۲۱ Enums, Readonly, Fibers, Intersection Types ۲۳٪ سریع‌تر از 8.0
8.2 ۸ دسامبر ۲۰۲۲ readonly classes, DNF Types, Random Extension بهبود جزئی
8.3 ۲۳ نوامبر ۲۰۲۳ Typed Constants, json_validate, Override ۱۲٪ سریع‌تر از 8.2
8.4 ۲۱ نوامبر ۲۰۲۴ Property Hooks, Asymmetric Visibility, array_find ۸٪ سریع‌تر از 8.3
8.5 ۲۰ نوامبر ۲۰۲۵ Pipe Operator, Clone With, URI Extension ۶٪ سریع‌تر از 8.4

️ مسیر مهاجرت پیشنهادی

  • از PHP 7.4 به 8.0 – بزرگترین جهش: Union Types، Nullsafe، Match را به‌کار بگیرید و کدهای قدیمی را بازنویسی کنید.
  • 8.0 به 8.1 – Enums جایگزین ثابت‌های کلاسی شوند، Readonly برای اشیاء تغییرناپذیر استفاده شود.
  • 8.1 به 8.2 – کلاس‌ها را readonly کامل کنید و از نوع‌های DNF برای تایپ‌هینت پیچیده استفاده کنید.
  • 8.2 به 8.3 – از Typed Constants و json_validate بهره ببرید و متدهای override شده را با #[Override] علامت بزنید.
  • 8.3 به 8.4 – با Property Hooks و visibility نامتقارن، مدل‌های تمیزتری بسازید. توابع آرایه‌ای جدید را جایگزین foreach کنید.
  • 8.4 به 8.5 – عملگر Pipe زنجیره‌سازی توابع را ساده‌تر می‌کند. Clone With و NoDiscard، کنترل بیشتری می‌دهند.

PHP 8.0 – تاریخ انتشار: ۲۶ نوامبر ۲۰۲۰

لیست سریع ویژگی‌ها

  • Named Arguments
  • Attributes (صفات)
  • Constructor Property Promotion
  • Union Types
  • Match Expression
  • Nullsafe Operator
  • JIT Compilation
  • مقایسه‌های رشته‌ای منطقی‌تر (Saner string comparisons)
  • توابع جدید: str_contains, str_starts_with, str_ends_with, get_debug_type

۱. Named Arguments (آرگومان‌های نام‌گذاری‌شده)

با Named Arguments می‌توانید آرگومان‌ها را بر اساس نام پارامتر ارسال کنید، نه صرفاً ترتیب. این کار خوانایی را بالا می‌برد و مقداردهی پارامترهای اختیاری را آسان می‌کند.

قبل (PHP 7.x): فقط ارسال بر اساس ترتیب ممکن بود؛ برای رد کردن یک پارامتر اختیاری باید مقادیر پیش‌فرض را تکرار می‌کردیم.

<?php
// روش قدیمی - مجبوریم تمام آرگومان‌های قبلی را پر کنیم
$result = htmlspecialchars($string, ENT_QUOTES | ENT_HTML5, 'UTF-8', false);
echo $result;
?>

بعد (PHP 8.0): با آرگومان نام‌گذاری‌شده، می‌توانیم فقط پارامتر double_encode را تغییر دهیم.

<?php
$string = '<a href="test">Test</a>';
// فقط پارامتر double_encode را با نام تنظیم می‌کنیم
$result = htmlspecialchars($string, double_encode: false);
echo $result; // خروجی: &lt;a href=&quot;test&quot;&gt;Test&lt;/a&gt;
?>

توضیح خط به خط:

  • htmlspecialchars($string, double_encode: false); پارامتر $string به‌عنوان آرگومان اول (موقعیتی) و double_encode به‌صورت نام‌گذاری‌شده ارسال می‌شود. بقیه پارامترها مقادیر پیش‌فرض خود را می‌گیرند.

۲. Attributes (صفات)

Attributes جایگزین مدرن برای docblock annotations هستند و به شما اجازه می‌دهند متادیتا را مستقیماً در کد با ساختار زبان ثبت کنید.

قبل (PHP 7.x): از کامنت‌های docblock برای تعریف Route استفاده می‌شد که در زمان اجرا پردازش می‌شدند.

<?php
/**
 * @Route("/api/posts", methods={"GET"})
 */
class PostController {
    // ...
}
?>

بعد (PHP 8.0): با Attributes، متادیتا کامپایل و بهینه‌سازی می‌شود.

<?php
#[Route('/api/posts', methods: ['GET'])]
class PostController {
    // ...
}

// تعریف ساده Attribute
#[Attribute]
class Route {
    public function __construct(
        public string $path,
        public array $methods = []
    ) {}
}

// خواندن Attribute از کلاس
$reflection = new ReflectionClass(PostController::class);
$attributes = $reflection->getAttributes(Route::class);
foreach ($attributes as $attr) {
    $route = $attr->newInstance();
    echo $route->path;      // خروجی: /api/posts
    echo implode(',', $route->methods); // خروجی: GET
}
?>

توضیح خط به خط:

  • #[Route('/api/posts', methods: ['GET'])] یک Attribute روی کلاس اعمال می‌کند.
  • با Reflection می‌توانیم آن را در زمان اجرا واکشی کنیم (getAttributes).

۳. Constructor Property Promotion (ترفیع خصوصیت‌ها در سازنده)

با این ویژگی دیگر نیازی به نوشتن جداگانه property و تخصیص آن در سازنده نیست.

قبل (PHP 7.x): کد تکراری برای تعریف و مقداردهی.

<?php
class Point {
    private float $x;
    private float $y;

    public function __construct(float $x, float $y) {
        $this->x = $x;
        $this->y = $y;
    }
}
$p = new Point(1.5, 2.5);
?>

بعد (PHP 8.0): ترکیب تعریف و تخصیص در یک جا.

<?php
class Point {
    public function __construct(
        private float $x,
        private float $y
    ) {}
}

$p = new Point(1.5, 2.5);
echo $p->x; // دسترسی مجاز (اگر public باشد)
// برای private، با var_dump بررسی می‌کنیم:
// var_dump($p); // خروجی: object(Point)#1 (2) { ["x":"Point":private]=> float(1.5) ["y":"Point":private]=> float(2.5) }
?>

۴. Union Types (انواع اتحادیه)

به پارامترها و مقادیر بازگشتی امکان می‌دهند چند نوع مختلف بپذیرند.

قبل (PHP 7.x): با docblock شبیه‌سازی می‌شد، اما در زمان اجرا اجباری نبود.

<?php
class Number {
    /** @var int|float */
    private $value;

    /** @param int|float $value */
    public function setValue($value) {
        if (!is_int($value) && !is_float($value)) {
            throw new TypeError;
        }
        $this->value = $value;
    }
}
?>

بعد (PHP 8.0): نوع‌دهی دقیق با int|float.

<?php
class Number {
    private int|float $value;

    public function setValue(int|float $value): void {
        $this->value = $value;
    }

    public function getValue(): int|float {
        return $this->value;
    }
}

$n = new Number();
$n->setValue(10);
$n->setValue(3.14);
echo $n->getValue(); // خروجی: 3.14
?>

توضیح خط به خط:

  • int|float $value یعنی پارامتر می‌تواند از نوع int یا float باشد.
  • نوع بازگشتی int|float نیز اتحادیه را نشان می‌دهد.

۵. Match Expression (عبارت انطباق)

Match Expression جایگزینی قدرتمند و امن برای switch است که مقدار بازمی‌گرداند و نیازی به break ندارد.

قبل (PHP 7.x): استفاده از switch با break.

<?php
$status = 'active';
switch ($status) {
    case 'draft':
        $result = 'پیش‌نویس';
        break;
    case 'active':
        $result = 'فعال';
        break;
    case 'archived':
        $result = 'بایگانی شده';
        break;
    default:
        $result = 'نامشخص';
}
echo $result; // خروجی: فعال
?>

بعد (PHP 8.0): با match مستقیم‌تر و بدون خطای break فراموش‌شده.

<?php
$status = 'active';
$result = match($status) {
    'draft'    => 'پیش‌نویس',
    'active'   => 'فعال',
    'archived' => 'بایگانی شده',
    default    => 'نامشخص'
};
echo $result; // خروجی: فعال
?>

توضیح خط به خط:

  • match مقدار $status را با هر case مقایسه می‌کند و اولین تطابق را برمی‌گرداند.
  • برخلاف switch، مقایسه‌ها === (دقیق) هستند و نیازی به break نیست.

۶. Nullsafe Operator (عملگر Nullsafe)

به شما اجازه می‌دهد بدون بررسی‌های پشت سر هم null، به زنجیره‌ی خواص و متدها دسترسی داشته باشید.

قبل (PHP 7.x): شرط‌های تودرتو برای جلوگیری از خطا.

<?php
$country = null;
if ($session !== null) {
    $user = $session->getUser();
    if ($user !== null) {
        $address = $user->getAddress();
        if ($address !== null) {
            $country = $address->getCountry();
        }
    }
}
echo $country ?? 'نامشخص'; // خروجی: نامشخص
?>

بعد (PHP 8.0): با ?-> کل زنجیره در یک خط.

<?php
$session = null; // فرض کنید نشست وجود ندارد
$country = $session?->getUser()?->getAddress()?->getCountry();
echo $country ?? 'نامشخص'; // خروجی: نامشخص

// حالتی با نشست واقعی (نیاز به کلاس‌های فرضی)
// اما خروجی nullsafe در صورت null بودن هر مرحله، null خواهد بود.
?>

توضیح خط به خط:

  • $session?->getUser() اگر $session نال باشد، کل عبارت null برمی‌گرداند و ادامه زنجیره اجرا نمی‌شود.

۷. JIT Compilation (کامپایل درجا)

JIT با کامپایل کردن بایت‌کد به کد ماشین در زمان اجرا، کارایی برخی عملیات را به‌شدت افزایش می‌دهد.

قبل (PHP 7.x): فقط موتور Zend VM بدون کامپایل درجا.

بعد (PHP 8.0): JIT از طریق OPcache با پیکربندی opcache.jit_buffer_size فعال می‌شود.
برای مثال، یک محاسبه‌ی ریاضی سنگین:

<?php
function compute(int $iterations): float {
    $x = 0.0;
    for ($i = 0; $i < $iterations; $i++) {
        $x += sqrt($i) * sin($i);
    }
    return $x;
}

$start = microtime(true);
compute(2_000_000);
$end = microtime(true);
echo "زمان اجرا: " . ($end - $start) . " ثانیه";
?>

نتایج بنچمارک (تقریبی):

حالت زمان (ثانیه)
بدون JIT 0.48
با JIT (tracing) 0.23
در سناریوهای محاسباتی تا ۲ برابر بهبود دیده شده است.

۸. مقایسه‌های رشته‌ای منطقی‌تر (Saner string comparisons)

در PHP 8.0 مقایسه‌ی یک رشته با عدد دیگر به‌طور نامنتظره 0 == "foobar" را true برنمی‌گرداند.

قبل (PHP 7.x): تبدیل عجیب باعث true می‌شد.

<?php
var_dump(0 == 'foobar'); // bool(true) – غیرمنتظره!
?>

بعد (PHP 8.0): مقایسه امن‌تر.

<?php
var_dump(0 == 'foobar'); // bool(false) - منطقی
var_dump(0 == '0');      // bool(true)  - همچنان درست
?>

۹. توابع جدید رشته‌ای

چهار تابع کاربردی برای کار با رشته‌ها معرفی شدند.

<?php
// str_contains – بررسی وجود زیررشته
var_dump(str_contains('Hello world', 'world')); // bool(true)

// str_starts_with – شروع با
var_dump(str_starts_with('PHP 8.0', 'PHP'));    // bool(true)

// str_ends_with – پایان با
var_dump(str_ends_with('index.php', '.php'));   // bool(true)

// get_debug_type – نوع دقیق متغیر برای دیباگ
$value = 42;
echo get_debug_type($value); // خروجی: int

$value = [1,2];
echo get_debug_type($value); // خروجی: array
?>

توضیح خط به خط:

  • str_contains جایگزین strpos() !== false شده است.
  • get_debug_type علاوه بر نوع، تفاوت بین int و float و … را بدون کلمه‌ی integer قدیمی نشان می‌دهد.

بهبود عملکرد در PHP 8.0

  • موتور JIT باعث بهبود ۱.۵ تا ۲ برابری در وظایف پردازشی سنگین می‌شود.
  • بهبودهای عمومی در OPcache، کامپایل و بهینه‌سازی آرایه‌ها.
  • اعداد دقیق بسته به نوع برنامه متغیر است.

تغییرات ناسازگار و منسوخ‌شده‌ها

  • حذف create_function().
  • تغییر رفتار (string) $float روی NaN و INF.
  • خطای TypeError برای [] ارسالی به پارامتر string.
  • match به‌عنوان کلمه‌ی کلیدی رزرو شده است.

توابع، کلاس‌ها و اینترفیس‌های جدید

  • توابع: str_contains, str_starts_with, str_ends_with, get_debug_type, get_resource_id
  • کلاس‌ها: Attribute, PhpToken, WeakMap
  • اینترفیس: Stringable

PHP 8.1 – تاریخ انتشار: ۲۵ نوامبر ۲۰۲۱

لیست سریع ویژگی‌ها

  • Enums (شمارشی‌ها)
  • Readonly Properties
  • First-class Callable Syntax
  • New in Initializers
  • Intersection Types
  • Never Return Type
  • Final Class Constants
  • Fibers (فیبرها)
  • Array Unpacking با کلیدهای رشته‌ای

۱. Enums (شمارشی‌ها)

Enums مجموعه‌ای از مقادیر ثابت و محدود را تعریف می‌کنند و می‌توانند متد و اینترفیس داشته باشند.

<?php
enum Status: string {
    case Draft = 'draft';
    case Active = 'active';
    case Archived = 'archived';

    public function label(): string {
        return match($this) {
            self::Draft    => 'پیش‌نویس',
            self::Active   => 'فعال',
            self::Archived => 'بایگانی شده',
        };
    }
}

$status = Status::Active;
echo $status->value; // خروجی: active
echo $status->label(); // خروجی: فعال
?>

توضیح خط به خط:

  • enum Status: string شمارشی با مقادیر رشته‌ای پشتیبان.
  • $status->value مقدار خام رشته‌ای را برمی‌گرداند.
  • متد label با match بر اساس نمونه عمل می‌کند.

۲. Readonly Properties (خصوصیت‌های فقط-خواندنی)

یک خصوصیت که فقط یک‌بار (در اعلان یا سازنده) مقداردهی می‌شود و دیگر تغییر نمی‌کند.

<?php
class BlogData {
    public readonly string $title;
    public readonly string $author;

    public function __construct(string $title, string $author) {
        $this->title  = $title;
        $this->author = $author;
    }
}

$post = new BlogData('PHP 8.1', 'Ali');
echo $post->title; // خروجی: PHP 8.1
// $post->title = 'changed'; // خطا: Cannot modify readonly property
?>

۳. First-class Callable Syntax (نحو فراخوانی درجه یک)

ایجاد Closure از یک تابع یا متد بدون استفاده از Closure::fromCallable یا آرایه‌های [$obj, 'method'].

قبل (PHP 7.x):

<?php
$fn = Closure::fromCallable('strlen');
echo $fn('hello'); // 5

$obj = new class {
    public function greet(string $name): string {
        return "Hello $name";
    }
};
$fn2 = Closure::fromCallable([$obj, 'greet']);
echo $fn2('Ali'); // Hello Ali
?>

بعد (PHP 8.1):

<?php
$fn = strlen(...);      // ایجاد بستار از strlen
echo $fn('hello');      // 5

$obj = new class {
    public function greet(string $name): string {
        return "Hello $name";
    }
};
$fn2 = $obj->greet(...); // بستار از متد نمونه
echo $fn2('Ali');        // Hello Ali
?>

توضیح خط به خط:

  • strlen(...) یک Closure برمی‌گرداند که strlen را صدا می‌زند.
  • $obj->greet(...) بستاری مقید به همان شیء می‌سازد.

۴. New in Initializers (استفاده از new در مقادیر پیش‌فرض)

حالا می‌توانید نمونه‌سازی اشیاء (و Enums و ...) را در مقدار پیش‌فرض پارامترها، خصوصیت‌ها و Attribute arguments انجام دهید.

<?php
class Logger {
    public function log(string $msg) { echo $msg; }
}

class Service {
    public function __construct(
        public Logger $logger = new Logger(), // مقدار پیش‌فرض جدید
    ) {}
}

$s = new Service();
$s->logger->log('Service started'); // خروجی: Service started
?>

همچنین در Attribute:

<?php
#[Attribute]
class Validation {
    public function __construct(public object $rule) {}
}

class MyRule {}

#[Validation(rule: new MyRule())] // مقداردهی با new در Attribute
function doSomething() {}
?>

۵. Intersection Types (انواع اشتراکی)

پارامتر باید همه‌ی اینترفیس‌های مشخص‌شده را پیاده‌سازی کند (با &).

<?php
function countAndIterate(Iterator&Countable $items): int {
    foreach ($items as $item) { /* ... */ }
    return count($items);
}

$arrayObject = new ArrayObject([1,2,3]);
echo countAndIterate($arrayObject); // خروجی: 3
?>

توضیح خط به خط:

  • Iterator&Countable یعنی آرگومان باید هم Iterator و هم Countable باشد.

۶. Never Return Type (نوع بازگشتی Never)

نشان می‌دهد که تابع/متد هرگز برنمی‌گردد (یا exit می‌کند یا استثناء پرتاب می‌کند).

<?php
function redirect(string $url): never {
    header("Location: $url");
    exit();
}

// redirect('https://example.com'); // هرگز به خط بعدی نمی‌رسد
// کد زیر فقط جهت نشان دادن:
function fail(): never {
    throw new Exception('خطا');
}
// fail(); // کد پس از فراخوانی اجرا نمی‌شود
?>

۷. Final Class Constants (ثابت‌های کلاسی نهایی)

ثابت‌های final در کلاس‌های فرزند قابل بازنویسی نیستند.

<?php
class Base {
    final public const VERSION = '1.0';
}

class Child extends Base {
    // public const VERSION = '2.0'; // خطا: Cannot override final constant
}

echo Child::VERSION; // خروجی: 1.0
?>

۸. Fibers (فیبرها)

فیبرها امکان تعلیق و ازسرگیری اجرای یک تابع را بدون مسدود کردن کل فرآیند فراهم می‌کنند.

<?php
$fiber = new Fiber(function (): void {
    $value = Fiber::suspend('اول');
    echo "بعد از تعلیق دریافت: $value\n";
});

$suspendedValue = $fiber->start();
echo "تعلیق شد با مقدار: $suspendedValue\n"; // خروجی: تعلیق شد با مقدار: اول

$fiber->resume('دوم');
// خروجی بعدی: بعد از تعلیق دریافت: دوم
?>

۹. Array Unpacking با کلیدهای رشته‌ای

اپراتور ... (spread) حالا از آرایه‌های دارای کلیدهای رشته‌ای نیز پشتیبانی می‌کند.

<?php
$array1 = ['a' => 1, 'b' => 2];
$array2 = ['c' => 3, 'a' => 0];

$result = [...$array1, ...$array2, 'd' => 4];
var_dump($result);
// خروجی: ['a' => 0, 'b' => 2, 'c' => 3, 'd' => 4]
// کلید 'a' با مقدار آخرین آرایه بازنویسی می‌شود.
?>

بهبود عملکرد (PHP 8.1)

  • اپلیکیشن Symfony Demo در PHP 8.1 حدود ۲۳٪ سریع‌تر از نسخه 8.0 اجرا می‌شود.
  • بهینه‌سازی‌های داخلی در پردازش match و مدیریت حافظه.

️ تغییرات ناسازگار و منسوخ‌شده‌ها

  • ارسال null به توابع داخلی که پارامتر non-nullable دارند منسوخ شده.
  • نوع‌های ضمنی int در float‌ها سخت‌گیرانه‌تر شده.
  • ReturnTypeWillChange برای سازگاری با PHP 9 لازم است.

توابع، کلاس‌ها و اینترفیس‌های جدید

  • Enums: پشتیبانی کامل از شمارشی‌ها.
  • Fiber: کلاس Fiber برای برنامه‌نویسی هم‌روند.
  • نوع‌ها: never, true (برای استفاده در union در آینده)، و Intersection Types.
  • توابع جدید: array_is_list(), fsync(), fdatasync().
  • اینترفیس‌ها: UnitEnum, BackedEnum.

PHP 8.2 – تاریخ انتشار: ۸ دسامبر ۲۰۲۲

لیست سریع ویژگی‌ها

  • Readonly Classes
  • DNF (Disjunctive Normal Form) Types
  • null, false و true به‌عنوان نوع‌های مستقل
  • Random Extension بهبودیافته با Randomizer
  • Constants in Traits
  • منسوخ‌شدن Dynamic Properties

۱. Readonly Classes

تمام خصوصیت‌های یک کلاس به‌طور خودکار readonly می‌شوند.

<?php
readonly class BlogData {
    public string $title;
    public string $author;

    public function __construct(string $title, string $author) {
        $this->title  = $title;
        $this->author = $author;
    }
}

$post = new BlogData('PHP 8.2', 'Sara');
echo $post->title; // خروجی: PHP 8.2
// $post->title = 'changed'; // خطا
?>

توضیح خط به خط:

  • کلمه readonly قبل از class همه خصوصیت‌های تعریف‌شده را فقط-خواندنی می‌کند.

۲. DNF Types (انواع به فرم نرمال فصلی)

نوع‌های ترکیبی از & و | که همیشه در فرم (A&B)|C (اتحاد از اشتراک‌ها) نوشته می‌شوند.

<?php
class A {}
class B extends A {}
interface C {}

function test((A&B)|null $param): void {
    var_dump($param);
}

$obj = new B();
test($obj); // شیء B که A و B را پوشش می‌دهد
test(null); // مجاز
?>

۳. null, false و true به‌عنوان نوع‌های مستقل

حالا می‌توانید false یا true را به‌عنوان نوع بازگشتی تنها استفاده کنید (و در union).

<?php
function alwaysFalse(): false {
    return false;
}

function maybeTrue(): true|false {
    return true;
}

var_dump(alwaysFalse()); // bool(false)
var_dump(maybeTrue());   // bool(true)
?>

۴. Random Extension و Randomizer

اکستنشن جدید random با کلاس Random\Randomizer و موتورهای مختلف (مثل Xoshiro256StarStar).

<?php
$randomizer = new Random\Randomizer(new Random\Engine\Xoshiro256StarStar());
echo $randomizer->getInt(1, 100); // یک عدد تصادفی بین ۱ تا ۱۰۰
echo "\n";
echo implode(', ', $randomizer->shuffleArray(['a','b','c'])); // آرایه تصادفی
?>

۵. Constants in Traits

می‌توانید در trait ثابت تعریف کنید و از آن در کلاس استفاده کنید.

<?php
trait LoggerTrait {
    public const LEVEL = 'INFO';
}

class App {
    use LoggerTrait;
}

echo App::LEVEL; // خروجی: INFO
?>

۶. منسوخ‌شدن Dynamic Properties

در 8.2، افزودن خصوصیت‌های پویا به کلاس‌هایی که __get/__set ندارند، منسوخ شده و اخطار تولید می‌کند.

<?php
class User {
    public string $name;
}

$user = new User();
$user->name = 'Ali';
// $user->email = 'ali@example.com'; // در PHP 8.2: Deprecated: Creation of dynamic property
// با خطای E_DEPRECATED مواجه می‌شویم.
?>

برای رفع: باید خصوصیت را تعریف کرد یا AllowDynamicProperties attribute را به کلاس اضافه کرد.


بهبود عملکرد

  • افزایش کارایی پردازش readonly و بهینه‌سازی‌های زمان کامپایل.

تغییرات ناسازگار

  • utf8_encode و utf8_decode منسوخ شدند.
  • mbstring دیگر خروجی E_WARNING برای کدگذاری‌های نامعتبر ندارد.

توابع، کلاس‌ها و اینترفیس‌های جدید

  • کلاس‌ها: Random\Randomizer, Random\Engine\Xoshiro256StarStar, Random\Engine\PcgOneseq128XslRr64, Random\Engine\Secure
  • اینترفیس: Random\Engine
  • توابع: mysqli_execute_query, openssl_cipher_key_length, curl_upkeep

PHP 8.3 – تاریخ انتشار: ۲۳ نوامبر ۲۰۲۳

لیست سریع ویژگی‌ها

  • Typed Class Constants
  • Dynamic Constant Fetch
  • #[Override] Attribute
  • Deep Cloning Readonly Properties
  • json_validate()
  • Randomizer::getBytesFromString() و getFloat()
  • CLI lint برای چند فایل

۱. Typed Class Constants

ثابت‌های کلاسی می‌توانند دارای نوع مشخص باشند.

<?php
class Config {
    public const string APP_NAME = 'MyApp';
    public const int MAX_USERS = 100;
}

echo Config::APP_NAME; // خروجی: MyApp
echo Config::MAX_USERS; // خروجی: 100
?>

۲. Dynamic Constant Fetch

دسترسی پویا به ثابت‌ها با استفاده از نام متغیر.

<?php
class Foo {
    public const string BAR = 'baz';
}

$constantName = 'BAR';
echo Foo::{$constantName}; // خروجی: baz
?>

۳. #[Override] Attribute

نشان می‌دهد که متدی در کلاس فرزند، متدی از والد را override می‌کند (جلوگیری از اشتباه تایپی).

<?php
class ParentClass {
    public function tearDown(): void {}
}

class Child extends ParentClass {
    #[Override]
    public function tearDown(): void {
        // اگر نام متد اشتباه نوشته شود، خطای کامپایل رخ می‌دهد
    }
}
?>

۴. Deep Cloning Readonly Properties

در متد __clone می‌توانید خصوصیت‌های readonly را دوباره مقداردهی کنید تا اشیاء تودرتو کلون شوند.

<?php
class Person {
    public function __construct(
        public readonly string $name,
        public readonly DateTime $birthDate
    ) {}

    public function __clone(): void {
        // در کلون مجازیم خصوصیت readonly را تغییر دهیم
        $this->birthDate = clone $this->birthDate;
    }
}

$original = new Person('Ali', new DateTime('2000-01-01'));
$clone = clone $original;
var_dump($clone->birthDate !== $original->birthDate); // true
?>

۵. json_validate()

اعتبارسنجی سریع رشته JSON بدون تبدیل به شیء/آرایه.

<?php
$json = '{"name": "Ali", "age": 30}';
var_dump(json_validate($json)); // bool(true)

$invalid = '{"name": "Ali",}';
var_dump(json_validate($invalid)); // bool(false)
?>

۶. Randomizer::getBytesFromString() و getFloat()

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

<?php
$randomizer = new Random\Randomizer();

$domain = $randomizer->getBytesFromString('abcdefghijklmnopqrstuvwxyz', 10);
echo "$domain.example.com"; // خروجی: مثلا kfghlqwxyz.example.com

$temperature = $randomizer->getFloat(-50.0, 60.0);
echo "دما: $temperature درجه"; // خروجی: یک عدد تصادفی بین -50 و 60
?>

۷. CLI Lint برای چند فایل

دستور php -l می‌تواند چندین فایل را همزمان بررسی کند.

$ php -l file1.php file2.php
No syntax errors detected in file1.php
No syntax errors detected in file2.php

بهبود عملکرد

  • Symfony Demo تا ۱۲٪ سریع‌تر از 8.2 اجرا می‌شود.
  • بهبود در json_validate و مدیریت حافظه.

️ تغییرات ناسازگار

  • UNSERIALIZE_* ثابت‌ها منسوخ شدند.
  • range() با string $end خطا می‌دهد اگر مقدار نامعتبر باشد.

توابع جدید

  • json_validate()
  • mb_str_pad()
  • stream_context_set_options()
  • Randomizer::getBytesFromString(), Randomizer::getFloat(), Randomizer::nextFloat()

PHP 8.4 – تاریخ انتشار: ۲۱ نوامبر ۲۰۲۴

لیست سریع ویژگی‌ها

  • Property Hooks (قلاب‌های خصوصیت)
  • Asymmetric Visibility (دید نامتقارن)
  • #[\Deprecated] Attribute
  • DOM API جدید (Dom\HTMLDocument)
  • BcMath\Number (اشیاء محاسباتی)
  • توابع آرایه‌ای: array_find, array_find_key, array_any, array_all
  • Subclasses PDO اختصاصی
  • new MyClass()->method() بدون پرانتز

۱. Property Hooks

به‌جای getter/setterهای دستی، می‌توانید مستقیماً منطق را در get و set خصوصیت تعریف کنید.

<?php
class Locale {
    private string $languageCode;

    public string $language {
        get => $this->languageCode;
        set {
            if (!preg_match('/^[a-z]{2}$/', $value)) {
                throw new InvalidArgumentException('کد زبان نامعتبر');
            }
            $this->languageCode = $value;
        }
    }

    public function __construct(string $language) {
        $this->language = $language; // از هوک set استفاده می‌کند
    }
}

$locale = new Locale('en');
echo $locale->language; // خروجی: en
// $locale->language = 'EN'; // خطا
?>

۲. Asymmetric Visibility

می‌توانید سطح دسترسی متفاوتی برای خواندن و نوشتن تعریف کنید.

<?php
class Versioned {
    public private(set) string $version = '1.0.0';

    public function upgrade(): void {
        $this->version = '1.0.1'; // نوشتن مجاز (داخل کلاس)
    }
}

$app = new Versioned();
echo $app->version; // مجاز: خواندن public
// $app->version = '2.0.0'; // خطا: نوشتن private
$app->upgrade();
echo $app->version; // 1.0.1
?>

۳. #[\Deprecated] Attribute

متدهای منسوخ‌شده را به‌وضوح علامت‌گذاری می‌کند و در IDE اخطار می‌دهد.

<?php
class Legacy {
    #[\Deprecated(reason: 'use getPhpVersion() instead')]
    public function oldVersion(): string {
        return '8.0';
    }

    public function getPhpVersion(): string {
        return '8.4';
    }
}

$legacy = new Legacy();
echo $legacy->oldVersion(); // در PHP 8.4: Deprecated: Function Legacy::oldVersion() is deprecated
?>

۴. DOM API جدید (Dom\HTMLDocument)

پارسر HTML مدرن با پشتیبانی از querySelector.

<?php
$html = <<<HTML
<html><body>
  <div class="content">Hello</div>
  <div class="footer">World</div>
</body></html>
HTML;

$doc = Dom\HTMLDocument::createFromString($html);
$element = $doc->querySelector('.content');
echo $element->textContent; // خروجی: Hello
?>

۵. BcMath\Number (اشیاء محاسباتی دقیق)

عملیات ریاضی با دقت دلخواه به‌صورت شیءگرا.

<?php
$num1 = new BcMath\Number('0.1');
$num2 = new BcMath\Number('0.2');
$sum = $num1 + $num2;
echo $sum; // خروجی: 0.3 (دقیق، نه 0.30000000000000004)

var_dump($num1 < $num2); // bool(true)
?>

۶. توابع آرایه‌ای جدید

چهار تابع قدرتمند برای جستجو و بررسی آرایه‌ها.

<?php
$numbers = [1, 2, 3, 4, 5];

$found = array_find($numbers, fn($n) => $n > 3);
echo $found; // خروجی: 4 (اولین عنصر منطبق)

$foundKey = array_find_key($numbers, fn($n) => $n > 3);
echo $foundKey; // خروجی: 3 (کلید)

var_dump(array_any($numbers, fn($n) => $n > 4)); // bool(true) - آیا حداقل یکی؟
var_dump(array_all($numbers, fn($n) => $n > 0)); // bool(true) - آیا همه؟
?>

۷. Subclasses PDO اختصاصی

درایورهای PDO حالا زیرکلاس‌های اختصاصی با متدهای ویژه دارند.

<?php
$pdo = new Pdo\Sqlite('sqlite::memory:');
$pdo->exec('CREATE TABLE test (id INT)');
$pdo->createFunction('double', fn($x) => $x * 2);
$stmt = $pdo->query("SELECT double(5)");
echo $stmt->fetchColumn(); // خروجی: 10
?>

۸. حذف پرانتز در new Class()->method()

دیگر نیازی به پرانتز دور new نیست.

<?php
class Greeter {
    public function greet(string $name): string {
        return "Hello $name";
    }
}

echo new Greeter()->greet('Ali'); // معتبر در PHP 8.4
// قبلاً باید می‌نوشتیم: (new Greeter())->greet('Ali')
?>

بهبود عملکرد

  • Symfony Demo ۸٪ سریع‌تر از 8.3.
  • بهبود در JIT و زمان اجرای توابع آرایه‌ای.

تغییرات ناسازگار

  • E_STRICT حذف شد.
  • round() با حالت‌های PHP_ROUND_HALF_* جدید دقیق‌تر.
  • bind_textdomain_codeset و چند تابع دیگر منسوخ شدند.

توابع و کلاس‌های جدید

  • array_find, array_find_key, array_any, array_all
  • Dom\HTMLDocument, Dom\XMLDocument
  • BcMath\Number
  • Pdo\Sqlite, Pdo\Mysql, Pdo\Pgsql
  • ReflectionMethod::hasPrototype()

PHP 8.5 – تاریخ انتشار: ۲۰ نوامبر ۲۰۲۵

لیست سریع ویژگی‌ها

  • URI Extension (Uri\Rfc3986\Uri)
  • Pipe Operator |>
  • Clone With clone(...)
  • #[\NoDiscard] Attribute
  • Closures in Constant Expressions
  • Persistent cURL Shares
  • array_first / array_last
  • Backtrace on Fatal Errors

۱. URI Extension

کلاس Uri\Rfc3986\Uri برای تجزیه و ساخت URL مطابق با RFC 3986.

<?php
$uri = new Uri\Rfc3986\Uri('https://example.com:8080/path?q=php#section');
echo $uri->getHost();   // خروجی: example.com
echo $uri->getPort();   // 8080
echo $uri->getPath();   // /path
echo $uri->getQuery();  // q=php
echo $uri->getFragment(); // section

// ساخت URL جدید
$newUri = $uri->withPath('/new')->withPort(null);
echo $newUri; // https://example.com/new?q=php#section
?>

۲. Pipe Operator |>

مقدار سمت چپ را به‌عنوان اولین آرگومان به تابع سمت راست پاس می‌دهد.

<?php
$input = '  PHP 8.5 rocks!   ';
$result = $input
    |> trim(...)
    |> str_replace('rocks', 'is amazing', ...)
    |> strtoupper(...);

echo $result; // خروجی: PHP 8.5 IS AMAZING!
?>

توضیح خط به خط:

  • $input |> trim(...) معادل trim($input).
  • خروجی آن به str_replace بعدی پاس داده می‌شود.

۳. Clone With

ایجاد کلون یک شیء با تغییرات مشخص روی خصوصیت‌ها در همان لحظه.

<?php
class Color {
    public function __construct(
        public int $red,
        public int $green,
        public int $blue,
        public int $alpha = 255
    ) {}

    public function withAlpha(int $alpha): static {
        return clone($this, ['alpha' => $alpha]);
    }
}

$original = new Color(255, 0, 0, 128);
$opaque = $original->withAlpha(255);

echo $opaque->alpha; // 255
echo $original->alpha; // 128 (بدون تغییر)
?>

۴. #[\NoDiscard] Attribute

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

<?php
class Version {
    #[\NoDiscard('version info should not be ignored')]
    public static function get(): string {
        return '8.5';
    }
}

Version::get(); // Warning: The return value of Version::get() should not be discarded
echo Version::get(); // استفاده صحیح - بدون اخطار
?>

۵. Closures in Constant Expressions

می‌توانید بستارها را در مقادیر ثابت، مقداردهی اولیه خصوصیت‌ها و Attribute arguments استفاده کنید.

<?php
#[Attribute]
class Handler {
    public function __construct(public \Closure $callback) {}
}

#[Handler(static function (string $msg) {
    echo "Handler called: $msg";
})]
class MyService {}

$ref = new ReflectionClass(MyService::class);
$attr = $ref->getAttributes(Handler::class)[0]->newInstance();
($attr->callback)('test'); // خروجی: Handler called: test
?>

۶. Persistent cURL Shares

با curl_share_init_persistent می‌توانید اشتراک‌ها را بین درخواست‌ها حفظ کنید.

<?php
$share = curl_share_init_persistent('my-global-share');
curl_share_setopt($share, CURLSHOPT_SHARE, CURL_LOCK_DATA_COOKIE);

$ch1 = curl_init('https://example.com');
curl_setopt($ch1, CURLOPT_SHARE, $share);
// ...
// $ch2 نیز از همان share استفاده می‌کند و کوکی‌ها به اشتراک گذاشته می‌شوند.
?>

۷. array_first و array_last

اولین و آخرین عنصر آرایه را به‌سادگی برمی‌گردانند.

<?php
$fruits = ['apple', 'banana', 'cherry'];
echo array_first($fruits); // خروجی: apple
echo array_last($fruits);  // خروجی: cherry

// با callback برای شرط:
$numbers = [10, 20, 30, 40];
$firstLarge = array_first($numbers, fn($n) => $n > 15);
echo $firstLarge; // 20
?>

۸. Backtrace on Fatal Errors

خطاهای مرگبار حالا یک backtrace شامل می‌شوند تا دیباگ آسان‌تر شود.

<?php
function crash(): void {
    throw new Exception('fatal demo');
}
crash();
// در خروجی خطا، backtrace کامل نمایش داده می‌شود.
?>

بهبود عملکرد

  • Symfony Demo ۶٪ سریع‌تر از 8.4.
  • بهینه‌سازی‌های Pipe Operator و Cloning.

️ تغییرات ناسازگار

  • SplFixedArray دیگر ArrayAccess و Iterator را پیاده‌سازی نمی‌کند (از 8.5 حذف می‌شود).
  • توابع each() و convert_cyr_string() حذف شده‌اند.

توابع و کلاس‌های جدید

  • Uri\Rfc3986\Uri
  • array_first(), array_last()
  • curl_share_init_persistent()
  • Attribute #[\NoDiscard]
  • Pipe operator |>

جمع‌بندی و توصیه‌ها

PHP 8 هر نسخه‌اش گامی بلند به سمت زبانی مدرن، امن و سریع‌تر بوده است.
اگر هنوز روی نسخه‌های 7.x هستید، اکنون بهترین زمان برای مهاجرت به PHP 8.4 یا 8.5 است.
ویژگی‌هایی مانند Property Hooks، Enums و Pipe Operator ساختار کدتان را تمیزتر، تست‌پذیرتر و خواناتر می‌کند.
همچنین بهبودهای متوالی عملکرد (از ۲۳٪ تا ۶٪ در هر نسخه) باعث کاهش هزینه‌های سرور می‌شود.

برای شروع:

  • کد قدیمی را با Rector و PHP CS Fixer به‌روز کنید.
  • از json_validate به‌جای json_decode + json_last_error استفاده کنید.
  • switchهای پیچیده را به match و foreachهای جستجو را به array_find تبدیل کنید.
  • کلاس‌های داده را readonly تعریف کنید تا از تغییر ناخواسته جلوگیری شود.

منابع


ع

درباره نویسنده

علیرضا، توسعه‌دهنده فول‌استک Laravel، روی طراحی سیستم‌های واقعی، ساخت پلتفرم‌های خدماتی، فروشگاهی و معماری قابل توسعه تمرکز دارد. این وبلاگ بخشی از مسیر ثبت تجربه‌ها و تصمیم‌های فنی اوست.