DSL بلغة PHP: بناء لغات مخصصة للمجال لتحسين الأعمال

مدرب بايثون أونلاين للمبتدئين

تعلم Python بسهولة دون إرهاق نظري. حل مهام عملية مع التحقق التلقائي واكتب الكود مباشرة في المتصفح.

ابدأ الدورة

ماذا لو كان الكود يتحدث لغة عملك؟

\n\n

تخيل: مدير المبيعات يكتب شرط الخصم بلغة إنجليزية واضحة، والنظام يحوّله تلقائيًا إلى كود عملي. أو محاسب يصف حساب الضريبة بعبارة "إذا كان المبلغ أكبر من 1000 والعميل من الاتحاد الأوروبي، طبق نسبة 5%"، دون كتابة سطر واحد من PHP. يبدو هذا كخيال علمي؟ مرحبًا بك في عالم اللغات المخصصة للمجال (DSL) بلغة PHP.

\n\n

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

\n\n

ما هو DSL ولماذا تحتاجه في PHP؟

\n\n

DSL (Domain Specific Language) هي لغة مصممة خصيصًا لمهمة محددة. على عكس لغات البرمجة العامة (مثل PHP أو Java أو Python)، تتحدث DSL لغة مجال عملك. أمثلة: SQL لقواعد البيانات، التعبيرات المنتظمة للبحث عن الأنماط، HTML لبناء الصفحات.

\n\n

لماذا تحتاج إنشاء DSL بلغة PHP؟ ثلاثة أسباب رئيسية:

\n\n
    \n
  • الوضوح. كود DSL يبدو كتعليمات بالعربية أو الإنجليزية. لا حاجة لأن تكون مبرمجًا لفهم المنطق.
  • \n
  • الأمان. تتحكم في ما يمكن للمستخدم فعله. لا حاجة لاستخدام eval أو shell_exec.
  • \n
  • سرعة التطوير. يمكن لمحللي الأعمال والمديرين وصف القواعد بأنفسهم، دون إلهاء فريق التطوير.
  • \n
\n\n

في PHP، هناك طريقتان رئيسيتان لـ إنشاء لغات مخصصة للمجال: DSL داخلي (يُبنى على بناء جملة PHP) وDSL خارجي (يتطلب محللًا خاصًا به). سنبدأ بالأول — فهو أبسط ويغطي غالبًا 80% من المهام.

\n\n

الطريقة 1: DSL داخلي — Fluent Interface وسحر الدوال

\n\n

DSL الداخلي هو عندما تستخدم بناء جملة PHP ولكن تنظمه ليبدو كلغة طبيعية. الكلاسيكي هو fluent interface (الواجهة الانسيابية). لنكتب DSL لبناء استعلامات SQL، لتشعر بالسحر فورًا.

\n\n

مثال: DSL لبناء استعلامات SQL

\n\n

بدلاً من كتابة:

\n\n
$query = "SELECT * FROM users WHERE age > 18 AND city = 'Moscow' ORDER BY name ASC LIMIT 10";
\n\n

نريد الكتابة بهذا الشكل:

\n\n
$query = QueryBuilder::table('users')\n    ->select('*')\n    ->where('age', '>', 18)\n    ->where('city', '=', 'Moscow')\n    ->orderBy('name', 'ASC')\n    ->limit(10)\n    ->get();
\n\n

أوافقك الرأي، إنها تقرأ كجملة. التنفيذ بسيط: كل دالة تُرجع $this، وفي النهاية دالة get() تجمع النص.

\n\n
class QueryBuilder {\n    private array $parts = [];\n\n    public function table(string $name): self {\n        $this->parts['table'] = $name;\n        return $this;\n    }\n\n    public function select(string $columns = '*'): self {\n        $this->parts['select'] = $columns;\n        return $this;\n    }\n\n    public function where(string $column, string $operator, $value): self {\n        $this->parts['where'][] = "$column $operator " . (is_string($value) ? "'$value'" : $value);\n        return $this;\n    }\n\n    public function orderBy(string $column, string $direction = 'ASC'): self {\n        $this->parts['order'] = "$column $direction";\n        return $this;\n    }\n\n    public function limit(int $limit): self {\n        $this->parts['limit'] = $limit;\n        return $this;\n    }\n\n    public function get(): string {\n        $sql = "SELECT {$this->parts['select']} FROM {$this->parts['table']}";\n        if (!empty($this->parts['where'])) {\n            $sql .= " WHERE " . implode(' AND                

المدونات

توصيات الكتب