اكتب أصناف PHP 8 وفق أعرافها: ترقية الخصائص، readonly، البواني المُسمّاة وكائنات القيمة غير القابلة للتغيير.
افتح هذا الدرس في Kodokonأنت تكتب الأصناف منذ زمن طويل، لكن PHP 8 جعلت عدة عادات قديمة عفا عليها الزمن. وأبرزها: ترقية الخصائص في الباني. فإضافة كلمة مفتاحية لمستوى الوصول (private، protected، public) أمام وسيط الباني تنشئ الخاصية وتُسنِد إليها القيمة في خطوة واحدة. وهكذا تنكمش الكتل الثلاث المتكررة في الأسلوب القديم - التصريح، والوسيط، والإسناد - لتصبح كتلة واحدة.
<?php
declare(strict_types=1);
class LegacyProduct
{
private string $name;
private int $priceCents;
public function __construct(
string $name,
int $priceCents,
) {
$this->name = $name;
$this->priceCents = $priceCents;
}
}
final class Product
{
public function __construct(
private string $name,
private int $priceCents,
) {
}
public function label(): string
{
return sprintf(
'%s (%.2f EUR)',
$this->name,
$this->priceCents / 100,
);
}
}
$product = new Product('Keyboard', 4990);
echo $product->label();يظل مستوى الوصول أداتك الأولى للتغليف: private افتراضيًا، وprotected فقط إذا احتاج صنف ابن إلى الوصول، وpublic كحل أخير. ومنذ PHP 8.1، تضيف readonly ضمانة أقوى: إذ لا يمكن الكتابة إلى الخاصية إلا مرة واحدة، من داخل نطاق الصنف الذي يصرّح بها. وبدمجها مع الترقية، تُنتِج كائنات قيمة غير قابلة للتغيير في بضعة أسطر فقط: فأيّ "تغيير" يُرجِع نسخة جديدة، ما يُلغي الآثار الجانبية المشتركة.
<?php
declare(strict_types=1);
final class Money
{
public function __construct(
public readonly int $amount,
public readonly string $currency,
) {
}
public function add(Money $other): self
{
if ($other->currency !== $this->currency) {
throw new InvalidArgumentException(
'Currency mismatch'
);
}
return new self(
$this->amount + $other->amount,
$this->currency,
);
}
}
$total = (new Money(500, 'EUR'))
->add(new Money(250, 'EUR'));
echo $total->amount;أما على صعيد الدوال، فيسود نمطان بين المطوّرين ذوي الخبرة. البواني المُسمّاة: باني private مقترن بمصانع ساكنة (static factories) يجعل كل نيّة صريحة ويمنع الإنشاءات غير المتّسقة. الواجهات الانسيابية: إرجاع $this (قابل للتغيير) أو new self(...) (غير قابل للتغيير) يتيح لك سَلسَلة الاستدعاءات. والمفاضلة معروفة جيدًا: فالنسخة غير القابلة للتغيير أكثر أمانًا لكنها تخصّص كائنًا واحدًا لكل استدعاء - وهو أمر لا يُذكر في معظم الأماكن، لكنه قابل للقياس داخل حلقة كثيفة التنفيذ.
<?php
declare(strict_types=1);
final class User
{
private function __construct(
public readonly string $email,
public readonly string $role,
) {
}
public static function admin(string $email): self
{
return new self($email, 'admin');
}
public static function member(string $email): self
{
return new self($email, 'member');
}
}
$user = User::admin('lea@example.com');
echo $user->role;readonly؟