فرز مصفوفة الكائنات في PHP: من الفوضى إلى النظام في 5 دقائق
\n\nتخيل: أنت تبني موقعًا تعليميًا باستخدام PHP وحصلت على قائمة طلاب من قاعدة البيانات. كل طالب هو كائن له اسم وعمر ودرجات. تحتاج إلى عرضهم على الصفحة: الأكبر سنًا أولاً، أو العكس، الأصغر سنًا. أو ربما الفرز أبجديًا. كيف تفعل ذلك إذا كان لديك ليس مصفوفة أرقام بسيطة، بل مصفوفة كائنات؟
\n\nهذا السؤال هو من أكثر الأسئلة شيوعًا على Stack Overflow. آلاف المطورين، من المبتدئين إلى المحترفين، يواجهون مهمة «sort array of objects by one property». واليوم سنحلها مرة واحدة وإلى الأبد. بدون حشو، مع أمثلة حية وشروحات واضحة.
\n\nلماذا لا تعمل الدالة العادية sort()؟
\n\nلنفترض أن لدينا مصفوفة كائنات $students:
<?php\nclass Student {\n public $name;\n public $age;\n public $score;\n\n public function __construct($name, $age, $score) {\n $this->name = $name;\n $this->age = $age;\n $this->score = $score;\n }\n}\n\n$students = [\n new Student("آنا", 22, 85),\n new Student("إيفان", 20, 92),\n new Student("ماريا", 23, 78),\n new Student("بيتر", 21, 95)\n];\n?>\n\nإذا حاولت استدعاء sort($students)، فسيصدر PHP خطأ أو لن يفعل شيئًا. لماذا؟ لأن sort() تعرف كيفية مقارنة الأرقام والسلاسل النصية، لكنها لا تعرف كيفية مقارنة كائنين. تحتاج إلى توضيح: «قارن حسب الخاصية age» أو «قارن حسب name». لهذا، يوجد في PHP دالة خاصة — usort().
تعرف على: usort() — أداتك الرئيسية
\n\nتأخذ الدالة usort() وسيطين: المصفوفة نفسها ودالة المقارنة. يجب أن تعيد دالة المقارنة هذه:
- \n
- 0 إذا كان العنصران متساويين؛ \n
- رقمًا سالبًا إذا كان العنصر الأول أصغر من الثاني؛ \n
- رقمًا موجبًا إذا كان العنصر الأول أكبر من الثاني. \n
يبدو الأمر معقدًا؟ في الواقع هو بسيط. لنقم بفرز الطلاب حسب العمر (تصاعديًا):
\n\n<?php\nusort($students, function($a, $b) {\n return $a->age <=> $b->age;\n});\n\n// النتيجة: إيفان (20)، بيتر (21)، آنا (22)، ماريا (23)\n?>\n\nلاحظ العامل <=> (السفينة الفضائية). ظهر في PHP 7 ويجعل الفرز موجزًا للغاية. يقارن قيمتين ويعيد -1 أو 0 أو 1. هذا بالضبط ما تحتاجه usort().
الفرز تنازليًا: تغيير الإشارة
\n\nهل تريد الفرز من الأكبر إلى الأصغر سنًا؟ ببساطة قم بتبديل المعاملين في العامل <=>:
\n\n<?php\nusort($students, function($a, $b) {\n return $b->age <=> $a->age; // الآن b يُقارن مع a\n});\n\n// النتيجة: ماريا (23)، آنا (22)، بيتر (21)، إيفان (20)\n?>\n\nأو، وهو نفس الشيء، اضرب النتيجة في -1:
\n\n<?php\nusort($students, function($a, $b) {\n return -($a->age <=> $b->age);\n});\n?>\n\nالفرز حسب السلاسل النصية (أبجديًا)
\n\nماذا لو كانت الخاصية سلسلة نصية؟ على سبيل المثال، الاسم. نفس المبدأ، لكن بدلاً من <=> نستخدم strcmp() أو strcasecmp() (للمقارنة غير الحساسة لحالة الأحرف):
<?php\n// أبجديًا (أ-ي)\nusort($students, function($a, $b) {\n return strcmp($a->name, $b->name);\n});\n\n// النتيجة: آنا، إيفان، ماريا، بيتر\n\n// أبجديًا (ي-أ) — ترتيب عكسي\nusort($students, function($a, $b) {\n return strcmp($b->name, $a->name);\n});\n?>\n\nالفرز حسب خاصية رقمية: بديل لـ <=>
\n\nالعامل <=> مناسب، لكن إذا كنت تعمل مع PHP قديم (قبل 7.0)، فهو غير موجود. في هذه الحالة، نكتب المقارنة يدويًا: