الفئات والكائنات

لقد كتبت 21 درسًا من الكود الإجرائي، وربما بدأت تشعر أن الأمور أصبحت فوضوية مع نمو قاعدة الكود الخاصة بك. البرمجة الموجهة للكائنات (OOP) تحل هذه المشكلة — فهي تجمع البيانات والوظائف ذات الصلة في «فئات»، مما يجعل الكود أكثر تنظيمًا وقابلية لإعادة الاستخدام.

1. لماذا نحتاج إلى الفئات والكائنات؟

فكر في الأمر من خلال تشبيه من واقع الحياة:

TEXT
Procedural: You follow a checklist every time you bake a cake — crack eggs → add flour → mix → bake
Object-oriented: You have a "cake machine" (class). Press "make" and out comes a cake (object)

دعونا نقارن بين الأكواد:

PHP
<?php
// Procedural: data and functions are scattered
$userName = "John";
$userAge = 25;
function greet($name) {
    return "Hello, {$name}";
}
echo greet($userName);

// Object-oriented: data and functions are bundled together
class User {
    public string $name;
    public int $age;
    
    function greet(): string {
        return "Hello, {$this->name}";
    }
}
$user = new User();
$user->name = "John";
$user->age = 25;
echo $user->greet();
?>
💡 نصيحة: البرمجة الموجهة للكائنات (OOP) ليست طريقة «أفضل» للبرمجة — إنها أداة لتنظيم الكود المعقد. تكون البرامج النصية الصغيرة أبسط عند استخدام الكود الإجرائي. وتصبح مزايا البرمجة الموجهة للكائنات واضحة بمجرد أن يتجاوز حجم قاعدة الكود الخاصة بك 500 سطر.


2. تعريف فئة

PHP
<?php
class Car {
    // Properties (data)
    public string $brand;
    public string $color;
    public int $year;
    
    // Methods (behavior)
    public function start(): string {
        return "{$this->brand} is starting!";
    }
    
    public function honk(): string {
        return "Beep beep!";
    }
}
?>

النقاط الرئيسية في قواعد الصياغة:


3. إنشاء الكائنات

الفئة ما هي إلا «مخطط». يمكنك إنشاء «كائنات» ملموسة باستخدام الكلمة الرئيسية new:

PHP
<?php
// From one blueprint (class), create three specific cars (objects)
$car1 = new Car();
$car1->brand = "Toyota";
$car1->color = "White";
$car1->year = 2024;

$car2 = new Car();
$car2->brand = "BMW";
$car2->color = "Black";
$car2->year = 2023;

echo $car1->start();  // Toyota is starting!
echo $car2->start();  // BMW is starting!

// Use the arrow operator -> to access properties and methods
echo $car1->brand;    // Toyota
$car1->color = "Red"; // Modify a property
echo $car1->color;    // Red
?>

4. طريقة __construct

يتم استدعاء منشئ الكائن تلقائيًا عند استخدام new، مما يتيح لك تهيئة الكائن:

PHP
<?php
class Car {
    public string $brand;
    public string $color;
    public int $year;
    
    // Constructor
    public function __construct(string $brand, string $color, int $year) {
        $this->brand = $brand;
        $this->color = $color;
        $this->year  = $year;
    }
    
    public function getInfo(): string {
        return "{$this->year} {$this->color} {$this->brand}";
    }
}

// Pass arguments when creating the object
$car = new Car("Toyota", "White", 2024);
echo $car->getInfo();  // 2024 White Toyota
?>
💡 نصيحة: في $this->brand = $brand، يمثل الجانب الأيسر $this->brand الخاصية، بينما يمثل الجانب الأيمن $brand المعلمة. يدعم PHP 8.0+ ترقية خصائص المنشئ، مما يجعل هذا الأمر أكثر وضوحًا — انظر أدناه.

▶ مثال: ترقية خصائص المنشئ في PHP 8

PHP
<?php
// PHP 8.0+ simplified syntax
class Car {
    public function __construct(
        public string $brand,
        public string $color,
        public int $year,
    ) {
        // Parameters automatically become properties! No more $this->brand = $brand
    }
}

$car = new Car("Toyota", "White", 2024);
echo $car->brand;  // Toyota ✅
?>
▶ جرّب الكود
💡 نصيحة: يُعد هذا أحد أكبر التحسينات في PHP 8 — حيث يقلل ترقية خصائص المنشئ من النص المتكرر إلى النصف. ينبغي استخدام هذه الصيغة في المشاريع الجديدة.


5. مُعدِّلات الوصول

تتحكم مُعدِّلات الوصول في مدى ظهور الخصائص والطرق:

PHP
<?php
class BankAccount {
    public string $bank = "Bank of China";  // Anyone can see and modify
    private float $balance = 0;             // Only accessible inside the class
    protected string $accountId;            // Accessible inside the class and subclasses
    
    public function __construct(
        private string $owner,
        private float $initialDeposit = 0.0
    ) {
        $this->balance = $initialDeposit;
    }
    
    // Safely manipulate private properties through public methods
    public function deposit(float $amount): void {
        if ($amount > 0) {
            $this->balance += $amount;
        }
    }
    
    public function getBalance(): float {
        return $this->balance;
    }
}

$account = new BankAccount("John", 1000);
echo $account->bank;         // Bank of China ✅ public is accessible
$account->deposit(500);       // ✅ public method can be called
echo $account->getBalance(); // 1500 ✅
// echo $account->balance;   // ❌ Error: private property not directly accessible
// $account->balance = 9999; // ❌ Error: can't arbitrarily change the balance
?>
المُعدِّل الاسم المستعار نطاق الوصول
public عام يمكن الوصول إليه من أي مكان
protected محمية الفئة الحالية والفئات الفرعية
private خاص الفصل الحالي فقط
💡 نصيحة: اجعل الخصائص private أو protected وقم بالوصول إليها من خلال طرق عامة — وهذا ما يُسمى بالتغليف. يتيح لك ذلك التحكم في كيفية تعديل البيانات؛ على سبيل المثال، يمكن أن تتضمن deposit() عملية التحقق من صحة البيانات.


6. مقارنة الكائنات

PHP
<?php
class User {
    public function __construct(
        public string $name,
        public int $age
    ) {}
}

$u1 = new User("John", 25);
$u2 = new User("John", 25);
$u3 = $u1;

var_dump($u1 == $u2);   // true (same property values)
var_dump($u1 === $u2);  // false (not the same object)
var_dump($u1 === $u3);  // true (pointing to the same object)
?>

7. مثال كامل: فئة المستخدم

▶ مثال: فئة مستخدم كاملة

PHP
<?php
class User {
    private string $passwordHash;  // Password hash—never exposed
    
    public function __construct(
        public string $username,
        public string $email,
        string $password,           // Regular parameter (not a property)
        public int $age = 0,
        public bool $isActive = true,
    ) {
        // Password is hashed during construction
        $this->passwordHash = password_hash($password, PASSWORD_DEFAULT);
    }
    
    public function verifyPassword(string $password): bool {
        return password_verify($password, $this->passwordHash);
    }
    
    public function getDisplayName(): string {
        return $this->username . ($this->isActive ? '' : ' (Deactivated)');
    }
    
    public function greet(): string {
        return "Hello, {$this->username}! Your email is {$this->email}.";
    }
}

// Usage
$user = new User("John", "john@example.com", "secret123", 25);

echo $user->greet();
echo "User status: " . $user->getDisplayName() . "<br>";

if ($user->verifyPassword("secret123")) {
    echo "Password correct!";
}
// echo $user->passwordHash; // ❌ Error: private, not accessible
?>
▶ جرّب الكود

❓ أسئلة شائعة

س متى يجب عليّ استخدام فئة مقابل دالة؟
ج استخدم فئة عندما تكون البيانات والدوال التي تعمل عليها مرتبطة ببعضها بشكل طبيعي. على سبيل المثال، يحتوي «المستخدم» على خصائص مثل الاسم والعمر والبريد الإلكتروني، بالإضافة إلى طرق تسجيل الدخول وتسجيل الخروج. أما إذا كان لديك فقط عدد قليل من الدوال المساعدة غير المرتبطة ببعضها، فلا بأس باستخدام الدوال العادية.
س ما هو $this؟
ج $this هو إشارة إلى «الكائن الحالي الذي يتم التعامل معه» داخل إحدى طرق الكائن. على سبيل المثال، داخل $car1->start()، يشير $this إلى $car1.
س لماذا لا نستخدم var لإعلان الخصائص؟
ج هذه صيغة خاصة بـ PHP 4 وقد عفا عليها الزمن. تستخدم لغة PHP الحديثة دائمًا public/private/protected مع إعلانات الأنواع.

📖 ملخص

📝 تمارين

  1. أنشئ فئة Book تحتوي على الخصائص title/author/price، ومنشئًا لتهيئة هذه الخصائص، وطريقة getInfo() تُرجع معلومات عن الكتاب.
  2. أنشئ فئة BankAccount تحتوي على متغير «الرصيد» خاص، وطريقتين عامتين للإيداع والسحب (لا يمكن أن يتجاوز السحب الرصيد)، وطريقة عامة للتحقق من الرصيد. أنشئ بعض الحسابات واختبر العمليات.
  3. أعد كتابة التمرين 1 باستخدام ميزة «ترقية خصائص المنشئ» في PHP 8. لاحظ عدد أسطر الكود التي ستوفرها.
Web-Tutorial.com

فريق Web-Tutorial التقني

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

100%