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请注意太空船操作符(<=>)——它出现在PHP 7.0中,使代码极其简洁。它返回-1、0或1,非常适合比较函数。
解析usort的工作原理
\n\nusort()函数接受两个参数:
- \n
- 数组(通过引用传递——原数组会被修改) \n
- 回调函数,用于比较两个元素 \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行代码缩减为1行。在支持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'的ASCII码(97)小于'B'的ASCII码(66)。对于不区分大小写的排序