ترتيب مصفوفة الكائنات في PHP: من المبتدئ إلى المحترف
\n\nتخيل الموقف: أنت تبني متجرًا إلكترونيًا باستخدام PHP. لديك مصفوفة من المنتجات، كل منتج هو كائن يحتوي على حقول مثل price و name و rating. يضغط المستخدم على "ترتيب حسب السعر"، وتحتاج إلى إعادة ترتيب هذه المصفوفة فورًا. كيف تفعل ذلك بشكل صحيح وأنيق؟ هذا هو موضوع تحليلنا اليوم.
موضوع ترتيب مصفوفة الكائنات حسب خاصية واحدة في PHP هو أحد أكثر الاستفسارات شيوعًا على Stack Overflow (ملايين المشاهدات!). ولا عجب: العمل مع الكائنات هو أساس PHP الحديث، والقدرة على ترتيب البيانات بمرونة هي مهارة لا غنى عنها. دعنا نشرح كل شيء من البسيط إلى المعقد، مع أمثلة حية وشروحات.
\n\nلماذا لا يمكنك استخدام sort() ببساطة؟
\n\nغالبًا ما يحاول المبتدئون استخدام sort() أو rsort() مع مصفوفة الكائنات. ويحصلون على خطأ أو نتيجة غير منطقية تمامًا. لماذا؟ لأن هذه الدوال تقارن العناصر كقيم بسيطة (أرقام أو نصوص)، بينما الكائن هو بنية معقدة. PHP لا يعرف أي حقل تريد الترتيب بناءً عليه: الاسم، السعر، أم التاريخ. تحتاج إلى تحديد قاعدة المقارنة بوضوح.
لهذا السبب تحديدًا توجد دوال usort() و uasort() و uksort(). الحرف "u" في الاسم يعني "user-defined" — دالة مقارنة يحددها المستخدم. نحن نكتب بأنفسنا كيفية مقارنة كائنين.
مثال أساسي: ترتيب المستخدمين حسب العمر
\n\nلنفترض أن لدينا كلاس User ومصفوفة من المستخدمين:
class User {\n public $name;\n public $age;\n \n public function __construct($name, $age) {\n $this->name = $name;\n $this->age = $age;\n }\n}\n\n$users = [\n new User('أحمد', 25),\n new User('خالد', 30),\n new User('ليلى', 22),\n new User('سامر', 28)\n];\n\nنحتاج إلى ترتيبهم تصاعديًا حسب العمر. نستخدم usort:
\n\nusort($users, function($a, $b) {\n return $a->age <=> $b->age;\n});\n\n// النتيجة:\n// ليلى (22), أحمد (25), سامر (28), خالد (30)\n\nلاحظ عامل المركبة الفضائية (spaceship operator) ( <=> ) — ظهر في PHP 7.0 ويجعل الكود موجزًا بشكل لا يصدق. يُرجع -1 أو 0 أو 1، وهو مثالي لدوال المقارنة.
شرح آلية عمل usort
\n\nتأخذ دالة usort() وسيطين:
- \n
- المصفوفة (تُمرر كمرجع — ستتغير المصفوفة الأصلية) \n
- دالة رد (Callback) تقارن بين عنصرين \n
يجب أن تُرجع دالة الرد:
\n- \n
- رقمًا سالبًا (عادةً -1) — إذا كان العنصر الأول أصغر من الثاني \n
- 0 — إذا كان العنصران متساويين \n
- رقمًا موجبًا (عادةً 1) — إذا كان العنصر الأول أكبر من الثاني \n
عامل المركبة الفضائية يقوم بذلك تلقائيًا. إليك كيف يبدو نفس الترتيب بدونه:
\n\nusort($users, function($a, $b) {\n if ($a->age == $b->age) return 0;\n return ($a->age < $b->age) ? -1 : 1;\n});\n\nالفرق واضح: العامل <=> يختصر 4 أسطر في سطر واحد. استخدمه في كل مكان حيث يكون إصدار PHP 7+ مدعومًا.
الترتيب حسب النصوص: مراعاة حالة الأحرف والإعدادات المحلية
\n\nالأرقام سهلة، لكن النصوص تتطلب عناية. لنرتب نفس المستخدمين حسب الاسم:
\n\nusort($users, function($a, $b) {\n return strcmp($a->name, $b->name);\n});\n\n// أو باستخدام عامل المركبة الفضائية:\nusort($users, function($a, $b) {\n return $a->name <=> $b->name;\n});\n\nلكن هناك تفصيل: عامل المركبة الفضائية يراعي حالة الأحرف. النص "apple" سيكون أصغر من "Banana"، لأن رمز الحرف 'a' (97) أصغر من 'B' (66). للترتيب غير الحساس لحالة الأحرف، استخدم strcasecmp():
usort($users, function($a, $b) {\n return strcasecmp($a->name, $b->name);\n});\n\nإذا كنت تتعامل مع نصوص عربية أو متعددة اللغات، فكر في استخدام Collator من مكتبة intl للترتيب الصحيح وفقًا للإعدادات المحلية.