مشروع تدريبي في البرمجة الكائنية
لقد درست 5 دروس في البرمجة الموجهة للكائنات. والآن دعنا ندمج كل هذه المعرفة معًا من خلال مشروعين: نظام مستخدم متكامل يغطي مفاهيم الوراثة/القوائم/السمات/الواجهات، وإطار عمل بسيط يمنحك لمحة أولية عن بنية MVC.
1. المشروع الأول: نظام إدارة أدوار المستخدمين
اجمع بين الفئات، والوراثة، والقوائم التعدادية، والسمات، والواجهات لإنشاء إطار عمل متكامل لإدارة أدوار المستخدمين.
▶ مثال: نظام مستخدم كامل قائم على البرمجة الكائنية
PHP
<?php
// === Enums ===
enum UserRole: string {
case ADMIN = 'admin';
case EDITOR = 'editor';
case MEMBER = 'member';
case GUEST = 'guest';
}
enum UserStatus: string {
case ACTIVE = 'active';
case INACTIVE = 'inactive';
case BANNED = 'banned';
}
// === Interfaces ===
interface Loggable {
public function getLogIdentifier(): string;
}
interface Manageable {
public function canAccess(string $resource): bool;
public function getPermissions(): array;
}
// === Traits ===
trait HasTimestamps {
public readonly string $createdAt;
public readonly string $updatedAt;
public function touch(): void {
$now = date("Y-m-d H:i:s");
if (!isset($this->createdAt)) {
$this->createdAt = $now;
}
$this->updatedAt = $now;
}
}
trait ArraySerializable {
public function toArray(): array {
return get_object_vars($this);
}
}
// === Base Class ===
abstract class User implements Loggable, Manageable {
use HasTimestamps, ArraySerializable;
public function __construct(
public readonly string $id,
public string $name,
public string $email,
public UserRole $role = UserRole::MEMBER,
public UserStatus $status = UserStatus::ACTIVE,
) {
$this->touch();
}
public function getLogIdentifier(): string {
return "User#{$this->id} ({$this->name})";
}
abstract public function canAccess(string $resource): bool;
abstract public function getPermissions(): array;
abstract public function getRoleLabel(): string;
}
// === Concrete Role Classes ===
class Admin extends User {
public function __construct(
string $id, string $name, string $email
) {
parent::__construct($id, $name, $email, UserRole::ADMIN);
}
public function canAccess(string $resource): bool {
return true; // Admin can access everything
}
public function getPermissions(): array {
return ['create', 'read', 'update', 'delete', 'manage_users', 'system_config'];
}
public function getRoleLabel(): string {
return '🔧 Admin';
}
}
class Editor extends User {
public function __construct(
string $id, string $name, string $email
) {
parent::__construct($id, $name, $email, UserRole::EDITOR);
}
public function canAccess(string $resource): bool {
return in_array($resource, ['articles', 'media', 'comments']);
}
public function getPermissions(): array {
return ['create', 'read', 'update', 'manage_comments'];
}
public function getRoleLabel(): string {
return '✏️ Editor';
}
}
class Member extends User {
public function __construct(
string $id, string $name, string $email
) {
parent::__construct($id, $name, $email, UserRole::MEMBER);
}
public function canAccess(string $resource): bool {
return in_array($resource, ['articles', 'comments', 'profile']);
}
public function getPermissions(): array {
return ['read', 'comment'];
}
public function getRoleLabel(): string {
return '👤 Member';
}
}
// === Access Manager ===
class AccessManager {
public function checkAccess(User $user, string $resource): string {
if ($user->status === UserStatus::BANNED) {
return "{$user->getRoleLabel()} {$user->name}: Banned, access denied for {$resource}";
}
$allowed = $user->canAccess($resource)
? "✅ Access Granted" : "❌ Access Denied";
return "{$user->getRoleLabel()} {$user->name}: {$allowed} {$resource}";
}
public function listAllAccess(array $users, array $resources): void {
foreach ($users as $user) {
echo "<h4>{$user->getLogIdentifier()}</h4>";
echo "Permissions: " . implode(', ', $user->getPermissions()) . "<br>";
foreach ($resources as $res) {
echo $this->checkAccess($user, $res) . "<br>";
}
}
}
}
// === Test the System ===
$users = [
new Admin("u1", "John", "admin@example.com"),
new Editor("u2", "Jane", "editor@example.com"),
new Member("u3", "Bob", "member@example.com"),
];
$resources = ['articles', 'media', 'comments', 'system_config', 'manage_users'];
$manager = new AccessManager();
$manager->listAllAccess($users, $resources);
// Test enum + serialization
echo "<br>Admin data: " . json_encode($users[0]->toArray(), JSON_UNESCAPED_UNICODE);
?>
2. المشروع الثاني: إطار عمل MVC بسيط
افهم مفهوم MVC المتمثل في «الموجه» (Router) و«وحدة التحكم» (Controller) و«العرض» (View) — فهذه هي الفكرة الأساسية الكامنة وراء أطر العمل مثل Laravel.
▶ مثال: نموذج MVC المصغر
PHP
<?php
// === Router ===
class Router {
private array $routes = [];
public function get(string $path, callable $handler): void {
$this->routes['GET'][$path] = $handler;
}
public function post(string $path, callable $handler): void {
$this->routes['POST'][$path] = $handler;
}
public function dispatch(string $method, string $uri): void {
$path = parse_url($uri, PHP_URL_PATH);
$handler = $this->routes[$method][$path] ?? null;
if ($handler) {
echo $handler($_GET);
} else {
http_response_code(404);
echo "<h2>404 — Page Not Found</h2>";
}
}
}
// === View Base ===
class View {
public static function render(string $template, array $data = []): string {
extract($data);
ob_start();
include __DIR__ . "/{$template}.php";
return ob_get_clean();
}
}
// === Controller Base ===
abstract class Controller {
protected function json(array $data, int $code = 200): void {
http_response_code($code);
header('Content-Type: application/json; charset=utf-8');
echo json_encode($data, JSON_UNESCAPED_UNICODE);
}
}
// === Concrete Controller ===
class HomeController extends Controller {
public function index(): void {
echo View::render('home', [
'title' => 'Home',
'message' => 'Welcome to my blog!',
]);
}
public function about(): void {
echo View::render('about', [
'title' => 'About Us',
'team' => ['John', 'Jane', 'Bob'],
'version' => '1.0.0',
]);
}
public function api(): void {
$this->json([
'status' => 'ok',
'data' => ['version' => '1.0.0', 'uptime' => time()],
]);
}
}
// === Set Up Routes ===
$router = new Router();
$home = new HomeController();
$router->get('/', fn() => $home->index());
$router->get('/about', fn() => $home->about());
$router->get('/api/status', fn() => $home->api());
// === Launch the App ===
$router->dispatch($_SERVER['REQUEST_METHOD'], $_SERVER['REQUEST_URI']);
?>
ملف العرض المرفق home.php:
PHP
<!DOCTYPE html>
<html lang="en">
<head><title><?= $title ?></title></head>
<body>
<h1><?= $message ?></h1>
<p>This page is built using MVC principles.</p>
</body>
</html>
3. التحول الفكري: من البرمجة الإجرائية إلى البرمجة الموجهة للكائنات
| التفكير الإجرائي | التفكير في البرمجة الكائنية |
|---|---|
"أحتاج إلى قراءة بيانات المستخدم" → كتابة دالة getUser() |
"ما هو المستخدم؟ ما هي خصائصه وسلوكياته؟" → تصميم فئة User |
| البيانات والوظائف موزعة على ملفات مختلفة | البيانات + السلوك مغلفة في فئة |
| تكرار في الكود → انسخ والصق أو استخرج دالة | تكرار في الكود → استخدم الوراثة أو السمات |
تمرير سلاسل 'admin' للأذونات |
تمرير UserRole::ADMIN كقائمة، مع ضمان سلامة الأنواع |
💡 نصيحة: البرمجة الموجهة للكائنات (OOP) هي وسيلة وليست غاية. ولا بأس بالبرمجة الإجرائية في البرامج النصية الصغيرة. انتقل إلى البرمجة الموجهة للكائنات عندما تلاحظ العلامات التالية: (1) استمرار تمرير نفس المعلمات بين الدوال؛ (2) تراكم المتغيرات العالمية؛ (3) استناد الشروط إلى «سلاسل النصوص» (
if ($role === 'admin')).
❓ أسئلة شائعة
س ما هي المهمة الفعلية لوحدة التحكم (Controller) في نموذج MVC؟
ج وحدة التحكم هي «مدير حركة المرور» — فهي تستقبل الطلب، وتستدعي النموذج (Model) للحصول على البيانات، وتختار العرض (View) لعرضه. وهي لا تتولى معالجة منطق الأعمال بنفسها (فهذه مهمة النموذج) ولا تكتب كود HTML (فهذه مهمة العرض).
س هل يجب أن أقوم بإنشاء إطار عمل خاص بي أم أستخدم إطار عمل موجود بالفعل؟
ج قم بإنشاء إطار عمل مصغر خلال مرحلة التعلم لفهم المبادئ (تمامًا مثل هذا الدرس). استخدم Laravel/Symfony في بيئة الإنتاج. بعد أن تقوم بإنشاء Router/Controller/View الخاص بك مرة واحدة، سيجعلك استخدام Laravel تقول: «آه، إذن هذا ما يحدث وراء الكواليس».
❓ أسئلة شائعة
س كيف يمكنني اختبار إطار العمل المصغر MVC الذي قمت بإنشائه؟
ج قم بتشغيل Apache أو خادم PHP المدمج (php -S localhost:8000)، ثم انتقل إلى http://localhost:8000 في متصفحك. يقوم الموزع (dispatcher) بتوجيه الطلب إلى وحدة التحكم المناسبة بناءً على عنوان URL. استخدم var_dump() أو error_log() لتصحيح الأخطاء خطوة بخطوة.
📖 ملخص
- يجمع نظام المستخدم بين جميع آليات البرمجة الموجهة للكائنات الخمس الرئيسية: القوائم، والوراثة، والواجهات، والسمات، والتعدد الشكلي
abstract class Userيحدد المخطط الأساسي للمستخدم؛ بينما تقوم الفئات الفرعية بتنفيذ قدرات الأدوار المحددة- يستخدم
AccessManagerالتعدد الشكلي للتحقق من الأذونات بشكل موحد عبر الأدوار المختلفة - مبدأ MVC: يقوم الموجه بتوزيع الطلبات → يقوم وحدة التحكم بالتنسيق → تقوم وحدة العرض بعرض النتائج
- البرمجة الكائنية (OOP) ليست حلاً سحريًّا — فكر في استخدامها عندما يتجاوز عدد أسطر الكود 500 سطر، أو عندما يحتوي على منطق متكرر، أو عندما يعتمد على متغيرات عامة
📝 تمارين
- استنادًا إلى نظام المستخدم، أضف دورًا باسم
Guest(يمكنه الوصول إلى المقالات فقط، ولا يمتلك أي أذونات تحرير على الإطلاق) وأضفه إلى مجموعة الاختبارات. - أضف طريقة
addRoute('GET/POST', $path, $handler)إلى جهاز التوجيه بحيث يمكن لمكالمة واحدة تسجيل كلتا الطريقتين. - أضف مكونًا
UserControllerإلى إطار عمل MVC يقوم بتنفيذ قائمة بالمستخدمين (يتم قراءتها من مصفوفة) وصفحة تفاصيل المستخدم (الاستعلام حسب المعرّف).



