إذا سألت مطوري PHP عن نوع الفرصة التي يرغبون في رؤيتها في PHP ، فسوف يتصل معظمهم بالأدوية.
سيكون الدعم العام على مستوى اللغة هو الحل الأفضل. لكن إدراكهم صعب . نأمل أن يصبح الدعم المحلي يومًا ما جزءًا من اللغة ، لكن من المحتمل أن يستغرق الأمر عدة سنوات حتى ننتظر.
ستوضح هذه المقالة كيف ، باستخدام الأدوات الموجودة ، في بعض الحالات مع الحد الأدنى من التعديلات ، يمكننا الحصول على قوة الأدوية الجنيسة في PHP الآن.
من المترجم: أستخدم عن قصد البحث عن ورقة من "الوراثة" الإنجليزية ، لأن لم أسمع أبدًا في التواصل أن شخصًا ما أطلق عليه "برمجة معممة".
المحتويات:
ما هي الأدوية
يغطي هذا القسم مقدمة موجزة للأدوية .
روابط القراءة:
مثال أبسط
نظرًا لأنه يتعذر حاليًا تحديد المواد الصيدلانية على مستوى اللغة ، فسوف يتعين علينا استخدام فرصة عظيمة أخرى - لتعريفها في كتل الرصيف.
نحن نستخدم هذا الخيار بالفعل في العديد من المشاريع. ألقِ نظرة على هذا المثال:
function createUsers(iterable $names): array { ... }
في الكود أعلاه ، نحن نفعل ما هو ممكن على مستوى اللغة. لقد حددنا معلمة $names
كشيء يمكن إدراجه. أشرنا أيضًا إلى أن الوظيفة ستقوم بإرجاع صفيف. سيقوم PHP بإلقاء TypeError
حالة عدم تطابق أنواع المعلمات وقيمة الإرجاع.
Docblock يحسن فهم الكود. يجب أن تكون $names
سلاسل ، ويجب أن ترجع الدالة صفيفًا من كائنات User
. فب نفسها لا تفعل مثل هذه الشيكات. لكن IDEs مثل PhpStorm يفهمون هذا الترميز ويحذروا المطور من أنه لم يتم احترام العقد الإضافي. بالإضافة إلى ذلك ، يمكن لأدوات التحليل الثابتة مثل Psalm و PHPStan و Phan التحقق من صحة البيانات المنقولة من وإلى الوظيفة.
الوراثة لتحديد مفاتيح وقيم الأنواع المذكورة
أعلاه هو أبسط مثال عام. تتضمن الأساليب الأكثر تعقيدًا القدرة على تحديد نوع مفاتيحها ، جنبًا إلى جنب مع نوع القيم. فيما يلي طريقة واحدة لوصف هذا:
function getUsers(): array { ... }
تقول هنا أن الصفيف الذي تم إرجاعه بواسطة getUsers
يحتوي على مفاتيح سلسلة وقيم type User
.
يفهم المحللون الثابتون مثل Psalm و PHPStan و Phan هذا التعليق التوضيحي ويأخذه في الاعتبار عند التحقق.
النظر في التعليمات البرمجية التالية:
function getUsers(): array { ... } function showAge(int $age): void { ... } foreach(getUsers() as $name => $user) { showAge($name); }
سيقوم المحللون showAge
بإلقاء تحذير على استدعاء showAge
مع وجود خطأ ، مثل هذا: Argument 1 of showAge expects int, string provided
.
لسوء الحظ ، في وقت كتابة هذا التقرير ، PhpStorm لا يعرف كيف.
الأدوية الأكثر تطوراً
نواصل الخوض في موضوع الوراثة. خذ بعين الاعتبار كائن مكدس :
class Stack { public function push($item): void { ... } public function pop() { ... } }
يمكن أن يقبل المكدس أي نوع من الكائنات. ولكن ماذا لو أردنا قصر المكدس على كائنات من النوع User
؟
المزمور وفان يدعمان التعليقات التوضيحية التالية:
class Stack { public function push($item): void; public function pop(); }
يتم استخدام docblock لنقل معلومات نوع إضافية ، على سبيل المثال:
$stack = new Stack(); Means that $userStack must only contain Users.
المزمور ، عند تحليل الكود التالي:
$userStack->push(new User()); $userStack->push("hello");
سوف يشكو من السطر 2 بسبب الخطأ Argument 1 of Stack::push expects User, string(hello) provided.
لا يدعم PhpStorm حاليًا هذا التعليق التوضيحي.
في الواقع ، لقد قمنا بتغطية جزء فقط من المعلومات حول الأدوية الجنيسة ، ولكن في الوقت الحالي هذا يكفي.
كيفية تنفيذ الأدوية بدون دعم لغوي
يجب إكمال الخطوات التالية:
- على مستوى المجتمع ، حدد المعايير العامة في مجموعات المرسى (مثل PSR الجديدة ، أو عُد إلى PSR-5)
- إضافة التعليقات التوضيحية dockblock إلى التعليمات البرمجية الخاصة بك
- استخدم IDEs التي تفهم هذه الاتفاقيات لإجراء تحليل ثابت في الوقت الحقيقي للعثور على التناقضات.
- استخدم أدوات التحليل الثابتة (مثل المزمور) كأحد خطوات CI لالتقاط الأخطاء.
- حدد طريقة لتمرير معلومات الكتابة إلى مكتبات الطرف الثالث.
التقييس
في الوقت الحالي ، اعتمد مجتمع PHP بشكل غير رسمي هذا التنسيق العام (يتم دعمه بواسطة معظم الأدوات ويكون معناها واضحًا لمعظم):
function getUsers(): array { ... }
ومع ذلك ، لدينا مشاكل مع أمثلة بسيطة مثل هذا:
function getUsers(): array { ... }
يتفهم المزمور ذلك ويعرف نوع المفتاح وقيم المصفوفة المرتجعة.
في وقت الكتابة ، PhpStorm لا يفهم هذا. باستخدام هذا الإدخال ، افتقد قوة التحليل الثابت في الوقت الحقيقي الذي يقدمه PhpStorm.
النظر في الكود أدناه. لا يفهم PhpStorm أن $user
من النوع User
و $name
هو من نوع السلسلة:
foreach(getUsers() as $name => $user) { ... }
إذا اخترت مزمور كأداة تحليل ثابتة ، يمكنني كتابة ما يلي:
function getUsers(): array { ... }
المزمور يفهم كل هذا.
يعرف PhpStorm أن متغير $user
هو من نوع User
. لكنه لا يزال لا يفهم أن مفتاح الصفيف يشير إلى سلسلة. لا يفهم Phan و PHPStan التعليقات التوضيحية الخاصة بالمزمور. الحد الأقصى الذي يفهمونه في هذا الرمز هو نفسه في PhpStorm: نوع $user
يمكنك القول أن PhpStorm يجب أن تقبل فقط array<keyType, valueType>
الاتفاق array<keyType, valueType>
. أنا لا أتفق معك ، لأنه أعتقد أن إملاء المعايير هذا هو مهمة اللغة والمجتمع ، ويجب أن تتبعها الأدوات فقط.
أفترض أن الاتفاقية الموضحة أعلاه سيتم استقبالها بحرارة من قبل معظم مجتمع PHP. أحد المهتمين في الأدوية. ومع ذلك ، تصبح الأمور أكثر تعقيدًا عندما يتعلق الأمر بالأنماط. لا يدعم PHPStan ولا PhpStorm حالياً القوالب. على عكس المزمور وفان. والغرض منها مماثل ، ولكن إذا قمت بحفر أعمق ، فستدرك أن التطبيقات مختلفة قليلاً.
كل خيار من الخيارات المقدمة هو نوع من التسوية.
ببساطة ، هناك حاجة إلى اتفاق على تنسيق السجل العام:
- أنها تحسن حياة المطورين. يمكن للمطورين إضافة مواد إلى رموزهم والاستفادة منها.
- يمكن للمطورين استخدام الأدوات التي يفضلونها والتبديل بينها (الأدوات) حسب الضرورة.
- يمكن لصانعي الأدوات إنشاء هذه الأدوات ذاتها ، وفهم الفوائد التي تعود على المجتمع وعدم الخوف من تغير شيء ما ، أو اتهامهم بـ "نهج خاطئ".
مزمور لديه كل الوظائف اللازمة لفحص الأدوية الجنيسة. فان كيندا من هذا القبيل ، أيضا.
أنا متأكد من أن PhpStorm ستقدم مواد جنائية بمجرد أن يأتي المجتمع باتفاقية تنسيق واحدة.
دعم كود الطرف الثالث
الجزء الأخير من اللغز العام هو إضافة دعم لمكتبات الطرف الثالث.
نأمل ، بمجرد ظهور معيار التعريف العام ، ستقوم معظم المكتبات بتنفيذه. ومع ذلك ، هذا لن يحدث على الفور. يتم استخدام بعض المكتبات ، ولكن ليس لديها دعم نشط. عند استخدام أجهزة التحليل الثابتة للتحقق من صحة الأنواع في الأدوية العامة ، من المهم أن يتم تحديد جميع الوظائف التي تقبلها هذه العناصر أو تُرجعها.
ماذا يحدث إذا كان مشروعك يعتمد على مكتبات تابعة لجهات خارجية ليس لديها دعم عام؟
لحسن الحظ ، تم حل هذه المشكلة بالفعل ، ووظائف كعب الروتين هي الحل. مزامير ، فان ، و PhpStorm دعم بذرة.
كعب الروتين هو ملفات عادية تحتوي على تواقيع للوظائف والأساليب ، لكن لا تنفذها. عن طريق إضافة كتل قفص الاتهام إلى كعب الروتين ، تحصل أدوات التحليل الثابتة على المعلومات الإضافية التي يحتاجون إليها. على سبيل المثال ، إذا كان لديك فئة مكدس دون تلميحات الكتابة والأدوية مثل هذا.
class Stack { public function push($item) { } public function pop() { } }
يمكنك إنشاء ملف كعب روتين له طرق متطابقة ، ولكن مع إضافة كتل قفص الاتهام ودون تنفيذ الوظائف.
class Stack { public function push($item); public function pop(); }
عندما يرى المحلل الثابت فئة المكدس ، فإنه يأخذ معلومات الكتابة من كعب الروتين ، وليس من الكود الفعلي.
ستكون القدرة على مشاركة رمز كعب الروتين (على سبيل المثال ، من خلال الملحن) مفيدة للغاية ، لأن سوف تسمح تقاسم العمل المنجز.
خطوات إضافية
يحتاج المجتمع إلى الابتعاد عن الاتفاقات ووضع المعايير.
ربما سيكون الخيار الأفضل هو PSR عام؟
أو ربما يمكن لمبدعي التحليلات الثابتة الرئيسية ، PhpStorm ، و IDEs الأخرى وأي من الأشخاص المعنيين بتطوير PHP (للتحكم) تطوير معيار يستخدمه الجميع.
بمجرد ظهور المعيار ، سيتمكن الجميع من المساعدة في إضافة مواد عامة إلى المكتبات والمشروعات الحالية ، مما يؤدي إلى إنشاء طلبات السحب. وحيث لا يكون ذلك ممكنًا ، يمكن للمطورين كتابة ومشاركة الروتين.
عند الانتهاء من كل شيء ، يمكننا استخدام أدوات مثل PhpStorm للتحقق من الأدوية العامة في الوقت الفعلي أثناء كتابة الرمز. يمكننا استخدام أدوات التحليل الثابتة كجزء من CI لدينا كضمان أمني.
يمكن أيضًا تنفيذ الأدوية العامة في PHP (جيدًا تقريبًا).
قيود
هناك عدد من القيود. PHP هي لغة ديناميكية تتيح لك القيام بالعديد من الأشياء "السحرية" ، مثل هذه . إذا كنت تستخدم الكثير من سحر PHP ، فقد يحدث أنه لا يمكن للمحللات الثابتة أن تستخرج بدقة جميع الأنواع في النظام. إذا كانت أي أنواع غير معروفة ، فلن تتمكن الأدوات من استخدام الأدوية بشكل صحيح في جميع الحالات.
ومع ذلك ، فإن التطبيق الرئيسي لهذا التحليل هو التحقق من صحة منطق عملك. إذا كتبت رمزًا نظيفًا ، يجب ألا تستخدم الكثير من السحر.
لماذا لا تقوم فقط بإضافة الأدوية الجنيسة إلى اللسان؟
سيكون هذا هو الخيار الأفضل. PHP لديه شفرة مفتوحة المصدر ، ولا أحد يزعجك لاستنساخ المصادر وتنفيذ الأدوية الجنيسة!
ماذا لو لم أكن بحاجة إلى الأدوية الجنيسة؟
فقط تجاهل كل ما سبق. واحدة من المزايا الرئيسية لـ PHP هي أنها مرنة في اختيار المستوى المناسب من تعقيد التنفيذ وفقًا لما تقوم بإنشائه. مع رمز لمرة واحدة ، لا تحتاج إلى التفكير في أشياء مثل الكتابة. ولكن في المشاريع الكبيرة ، يجدر استخدام مثل هذه الفرص.
شكرا لكل من قرأ هذا المكان. سأكون سعيدا لتعليقاتكم في PM.
محدث : ghost404 في التعليقات لاحظت أن PHPStan من الإصدار 0.12.x يفهم التعليقات التوضيحية للمزمور ويدعم الوراثة