الرئيسية تطوير الويب الوراثة ومستويات الوصول في PHP: بناء هيكل كود آمن وقابل لإعادة الاستخدام

الوراثة ومستويات الوصول في PHP: بناء هيكل كود آمن وقابل لإعادة الاستخدام

amr gamal أغسطس 28, 2026

في الدرس السابق من هذا المسار، تعرّفنا على أساسيات البرمجة كائنية التوجه (OOP) بلغة PHP، وكيفية إنشاء الصفوف (Classes) والكائنات (Objects)، واستخدام الدالة البانية (Constructor). لكن عند بناء تطبيقات ويب الحقيقية مثل المتاجر الإلكترونية أو أنظمة إدارة المحتوى ستجد أنك تكرر كتابة الخصائص والدوال نفسها في عدة صفوف متقاربة.

هنا يأتي دور مفهومين أساسيين من أعمدة الوراثة ومستويات الوصول (Access Modifiers). في هذا الدرس، ستتعلم كيف تنشئ علاقات هرمية بين الصفوف لإعادة استخدام الكود بكفاءة، وكيف تحمي بيانات تطبيقك وتتحكم في نطاق رؤيتها وتنفيذها.

الوراثة ومستويات الوصول في PHP

مفهوم مستويات الوصول (Access Modifiers) في PHP

مستويات الوصول هي كلمات مفتاحية تُحدد المكان الذي يمكن منه الوصول إلى خصائص (Properties) ودوال (Methods) الصف. يخدم هذا المفهوم مبدأ "الكبسلة" (Encapsulation)، وهو عدم كشف البيانات الداخلية للكائن إلا من خلال واجهات مخصصة وآمنة.

توفر لغة PHP ثلاثة مستويات رئيسية للوصول:

  • public (عام): يمكن الوصول إلى العنصر من أي مكان، سواء من داخل الصف، أو من الصفوف المشتقة منه، أو من خارج الصف تماماً عبر الكائن.
  • protected (محمي): يمكن الوصول إلى العنصر فقط من داخل الصف نفسه، أو من داخل الصفوف التي ترث منه (Child Classes)، ولا يمكن الوصول إليه مباشرة من خارج الكائن.
  • private (خاص): يمكن الوصول إلى العنصر فقط حكماً من داخل الصف الذي عُرّف فيه. لا يمكن للصفوف الوارثة ولا للكود الخارجي الوصول إليه.

لنراقب هذا السلوك عبر مثال برمجية بسيط يوضح الفروق الجوهرية بين هذه المستويات:

<?php

class Account {
    public string $username = "guest";
    protected string $email = "user@example.com";
    private string $passwordHash = "secret_hash_123";

    public function getDetails(): string {
        // يمكن الوصول لجميع المستويات من داخل الصف نفسه
        return "User: {$this->username}, Email: {$this->email}, Hash: {$this->passwordHash}";
    }
}

$user = new Account();

// 1. الوصول للخاصية العامة (مسموح)
echo $user->username; // يُطبع: guest

// 2. محاولة الوصول للخاصية المحمية (سيتسبب في خطأ Fatal Error)
// echo $user->email;

// 3. محاولة الوصول للخاصية الخاصة (سيتسبب في خطأ Fatal Error)
// echo $user->passwordHash;

// 4. استدعاء دالة عامة تقرأ البيانات الداخلية (مسموح)
echo $user->getDetails();
?>

شرح الكود:

في هذا المثال، تسمح الخاصية public بالتعديل والقراءة المباشرة من الخرج. بينما تُعطّل الخصائص protected و private أي محاولة قراءة أو تعديل تأتي من النطاق العام (Global Scope). الاستثناء الوحيد لقراءة الخصائص المحمية أو الخاصة هو عبر دوال عامة (Public Methods) يوفرها الصف نفسه، مثل الدالة getDetails().

مفهوم الوراثة (Inheritance) باستخدام الكلمة المفتاحية extends

الوراثة هي آلية تسمح لصف جديد (تلميذ/ابن Child Class) بالحصول على الخصائص والدوال الخاصة بصف قائم بالفعل (أب/أساس Base/Parent Class). تسمح لك هذه الميزة بكتابة المنطق المشترك مرة واحدة في الصف الأب، ثم توسيعه في الصفوف الابنة دون تكرار الكود (DRY - Don't Repeat Yourself).

في PHP، تُستخدم الكلمة المفتاحية extends لربط الصف الابن بالصف الأب. تجدر الإشارة إلى أن PHP تدعم الوراثة الأحادية فقط (Single Inheritance)، مما يعني أن الصف الابن يمكنه أن يرث من صف أب واحد فقط في نفس الوقت.

مثال عملي: نظام مستخدمي موقع الويب

لنبدأ بتصميم نظام إدارة مستخدمين لصفحة ويب، حيث يوجد لدينا نوعان من المستخدمين: مستخدم عادي (User) ومُشرف على النظام (Admin). المشرف هو مستخدم عادي يمتلك صلاحيات إضافية.

<?php

// الصف الأب (Base Class)
class User {
    protected string $name;
    protected string $email;

    public function __construct(string $name, string $email) {
        $this->name = $name;
        $this->email = $email;
    }

    public function getProfile(): string {
        return "الاسم: {$this->name} | البريد: {$this->email}";
    }
}

// الصف الابن (Child Class) يرث من User
class Admin extends User {
    private array $permissions;

    public function __construct(string $name, string $email, array $permissions = []) {
        // استدعاء الدالة البانية للصف الأب لتمرير البيانات الأساسية
        parent::__construct($name, $email);
        $this->permissions = $permissions;
    }

    public function getAdminInfo(): string {
        // يمكننا الوصول للخصائص name و email لأنها معرّفة كـ protected في الصف الأب
        $profile = $this->getProfile();
        $permList = implode(", ", $this->permissions);
        return "{$profile} | الصلاحيات: [{$permList}]";
    }
}

// إنشائ كائن من الصف الابن
$admin = new Admin("أحمد محمود", "ahmed@sitegeeky.com", ["delete_posts", "ban_users"]);

echo $admin->getProfile(); 
// مخرجات: الاسم: أحمد محمود | البريد: ahmed@sitegeeky.com

echo "<br>";

echo $admin->getAdminInfo();
// مخرجات: الاسم: أحمد محمود | البريد: ahmed@sitegeeky.com | الصلاحيات: [delete_posts, ban_users]
?>

تحليل كود الوراثة:

  • الكلمة المفتاحية extends: جعلت الصف Admin يكتسب الخصائص والدوال الخاصة بـ User.
  • الكلمة المفتاحية parent: استُخدمت داخل الدالة البانية لـ Admin كـ parent::__construct()، وذلك لضمان تنفيذ المنطق الموجود في بناء الصف الأب أولاً بدلاً من إعادة كتابته.
  • الوصول للخصائص المحمية: لو كانت $name و $email في الصف User معرّفة كـ private، لما استطاع الصف Admin قراءتها مباشرة. لذلك استخدمنا protected لتسهيل التوسعة في الصفوف المشتقة مع بقائها مخفية عن الخرج العام.

إعادة كتابة الدوال (Method Overriding)

قد يحتاج الصف الابن إلى تغيير طريقة عمل دالة ورثها من الصف الأب لتناسب متطلباته الخاصة. يُعرف هذا بـ "إعادة كتابة الدوال" أو (Method Overriding).

لإعادة كتابة دالة، يقوم الصف الابن بإنشاء دالة تحمل نفس الاسم ونفس التوقيع (Signature) الخاص بالدالة في الصف الأب.

<?php

class User {
    protected string $name;

    public function __construct(string $name) {
        $this->name = $name;
    }

    public function renderDashboard(): string {
        return "مرحباً بك {$this->name} في لوحة التحكم العادية.";
    }
}

class PremiumUser extends User {
    // إعادة كتابة الدالة لتشمل تخصيصات إضافية
    public function renderDashboard(): string {
        $baseText = parent::renderDashboard();
        return $baseText . " تم تفعيل ميزات العضوية المدفوعة!";
    }
}

$standard = new User("سارة");
echo $standard->renderDashboard();
// مخرجات: مرحباً بك سارة في لوحة التحكم العادية.

echo "<br>";

$vip = new PremiumUser("خالد");
echo $vip->renderDashboard();
// مخرجات: مرحباً بك خالد في لوحة التحكم العادية. تم تفعيل ميزات العضوية المدفوعة!
?>

في هذا المثال، استخدمنا parent::renderDashboard() للوصول إلى النتيجة الأصلية للصف الأب، ثم أضفنا نصاً جديداً إليها، مما حافظ على تسلسل منطق التطبيق بدون تكرار.

منع الوراثة أو التعديل باستخدام الكلمة المفتاحية final

في بعض أجزاء التطبيقات الحساسة—مثل دوال معالجة التشفير أو أجزاء منطق الأمان—قد ترغب في منع الصفوف الأخرى من الوراثة منك، أو منع إعادة كتابة دالة معينة. توفر PHP الكلمة المفتاحية final لهذا الغرض.

  • إذا وضعت final قبل اسم الصف، فلن يستطيع أي صف آخر أن ينفذ extends منه.
  • إذا وضعت final قبل اسم الدالة، فلن يستطيع أي صف ابن إعادة كتابة هذه الدالة (Overriding).
<?php

class SecuritySystem {
    // دالة نهائية لا يمكن إعادة كتابتها في أي صف مشتق
    final public function hashPassword(string $password): string {
        return password_hash($password, PASSWORD_BCRYPT);
    }
}

// صف نهائي كامل لا يمكن الوراثة منه
final class EncryptionHelper extends SecuritySystem {
    // حاول إعادة كتابة hashPassword وسيعطيك PHP خطأً نظامياً
}

// المحاولة التالية ستؤدي إلى خطأ سينتاكس فوري:
// class SubEncryption extends EncryptionHelper {} // Fatal Error
?>

تطبيق عملي: بناء نظام بوابات دفع إلكترونية (Payment Gateways)

لتوضيح الصورة بشكل أفضل ضمن سياق تطوير الويب المتقدم، لنبني نظاماً مصغراً للتعامل مع بوابات الدفع الإلكتروني (مثل PayPal و Stripe). يوضح هذا المثال كيف توفر الوراثة ومستويات الوصول بنية برمجية متماسكة وسهلة الصيانة.

<?php

// الصف الأساسي لجميع بوابات الدفع
abstract class PaymentGateway {
    protected string $apiKey;
    protected string $merchantId;

    public function __construct(string $apiKey, string $merchantId) {
        $this->apiKey = $apiKey;
        $this->merchantId = $merchantId;
    }

    // دالة تسجيل العمليات لغرض التتبع (Logging)
    protected function logTransaction(float $amount, string $status): void {
        // في الواقع يتم التخزين في قاعدة البيانات هنا
        echo "[LOG]: تم تنفيذ عملية بقيمة {$amount} - الحالة: {$status}<br>";
    }

    abstract public function processPayment(float $amount): bool;
}

// بوابة دفع PayPal
class PayPalGateway extends PaymentGateway {
    private string $paypalEmail;

    public function __construct(string $apiKey, string $merchantId, string $paypalEmail) {
        parent::__construct($apiKey, $merchantId);
        $this->paypalEmail = $paypalEmail;
    }

    public function processPayment(float $amount): bool {
        // منطق الاتصال بـ API الخاص بـ PayPal
        echo "جاري الاتصال بـ PayPal باستخدام الحساب {$this->paypalEmail}...<br>";
        
        // استدعاء دالة التسجيل المحمية من الصف الأب
        $this->logTransaction($amount, "SUCCESS");
        return true;
    }
}

// بوابة دفع Stripe
class StripeGateway extends PaymentGateway {
    public function processPayment(float $amount): bool {
        // منطق الاتصال بـ API الخاص بـ Stripe
        echo "جاري معالجة البطاقة عبر Stripe باستخدام المفتاح: " . substr($this->apiKey, 0, 5) . "...<br>";
        
        $this->logTransaction($amount, "SUCCESS");
        return true;
    }
}

// استخدام النظام في التطبيق
$paypal = new PayPalGateway("pay_secret_9988", "m_123", "billing@sitegeeky.com");
$paypal->processPayment(150.00);

echo "<hr>";

$stripe = new StripeGateway("sk_live_51Mz...", "m_456");
$stripe->processPayment(299.99);
?>

فوائد التصميم السابق:

  1. الأمان والكبسلة: الخصائص الحساسة مثل $apiKey محفوظة كـ protected، فلا يمكن لأي كود خارجي تعديل المفاتيح أثناء العمل.
  2. تقليل التكرار: دالة تسجيل العمليات logTransaction ومفاتيح الدخول عُرّفت مرة واحدة في الصف الأب واستُخدمت في الصفوف الفرعية.
  3. قابلية التوسع: لإضافة بوابة دفع جديدة (مثل Tap أو Moyasar)، يكفي إنشاء صف جديد ينفذ extends PaymentGateway دون المساس بالكود القديم.

أخطاء شائعة عند التعامل مع الوراثة ومستويات الوصول

  • جعل جميع الخصائص Public: يقع المبتدئون في خطأ جعل جميع المتغيرات public لتفادي مشاكل الوصول. يكسر هذا مبدأ الكبسلة ويجعل تتبع أخطاء تعديل البيانات صعبة للغاية في المشاريع الكبيرة.
  • التعمق المفرط في شجرة الوراثة (Deep Inheritance): إنشائ سلاسل وراثة طويلة جداً (مثلاً الصف A يمتد من B، و B من C، و C من D...) يجعل الكود معقداً وصعب القراءة والصيانة. يُفضل إبقاء التسلسل الهرمي ضيقاً وضحلاً.
  • نسيان استدعاء الباني الأب (Parent Constructor): عند كتابة __construct في الصف الابن، ينبغي ألا تنسى استدعاء parent::__construct() إذا كان الصف الأب يتطلب تهيئة خصائص ضرورية.
  • خلط Private مع Protected: إذا كنت تخطط لإنشاء صفوف فرعية تعتمد على خصائص الأب، فلا تجعل تلك الخصائص private، بل استخدم protected.

خلاصة الدرس

تُعد الوراثة ومستويات الوصول أداة تنظيمية وأمنية لا غنى عنها عند التفكير بمنطق OOP في PHP. بفضل الوراثة، تصبح بناء الأنظمة المعقدة أكثر سلاسة من خلال إعادة استخدام الكود المكتوب سابقاً، بينما تضمن لك مستويات الوصول عدم عبث الأجزاء الخارجية ببيانات الكائنات الداخلية.

في الدرس القادم، سننتقل إلى مرحلة أكثر تقدماً في التصميم والمعمارية عبر دراسة الصفوف المجرّدة (Abstract Classes) والواجهات (Interfaces)، وكيف يحددان العقود (Contracts) البرمجية داخل تطبيقات الويب المتكاملة.

التصنيفات:
الكاتب
عمرو جمال

محرر متخصص في تطوير قوالب بلوجر وووردبريس وتقديم شروحات التقنية. أقدم حلولاً مبتكرة لتصميم مواقع عصرية وجذابة.