如何在PHP中对对象数组进行排序?

时间:2009-10-06 23:05:44

标签: php arrays oop sorting

假设我有一群人,每个人都有姓名,性别和年龄属性,编码如下:

public class Person
{
   private $name, $sex, $age;
   public function Person ($name, $sex, $age)
   {
       $this->name = $name;
       $this->sex = $sex;
       $this->age = $age;
   }
   public function getName();    
   public function getSex();
   public function getAge();
}

public class People
{
   private $people = array();
   public function addPerson ($name, $sex, $age)
   {
      $this->people[] = new Person($name, $sex, $age);
   }
}

我如何实现一个方法sortPeople(),它将$people数组按人名的升序排序到People类?

3 个答案:

答案 0 :(得分:8)

这是一个带有静态方法的工作代码。它还使用静态方法可以访问私有ivars的事实:) 它还使用PHP令人敬畏的反身性<3。

关于该代码的好处是Person是提供排序方法的类,在OOP观点上更好。只有班级Person应该知道如何对其他Person进行排序。 People或其他独立函数都不应该。

注意:不使用is_callable(),因为它只验证参数是否可以作为函数调用,但不检查它是否可以使用当前可见性(公共,私有,受保护)实际调用

class Person
{
    private $name, $sex, $age;
    public function Person($name, $sex, $age)
    {
        $this->name = $name;
        $this->sex = $sex;
        $this->age = $age;
    }

    public static function sortByName(Person $p1, Person $p2)
    {
        return strcmp($p1->name, $p2->name);
    }

    public static function sortByAge(Person $p1, Person $p2)
    {
        return ($p1->age - $p2->age);
    }
}

class People
{
    private $people = array();
    public function addPerson($name, $sex, $age)
    {
        $this->people[] = new Person($name, $sex, $age);
    }

    public function display()
    {
        print_r($this->people);
    }

    public function sort($attribute = 'name')
    {
        $sortFct = 'sortBy' . ucfirst(strtolower($attribute));
        if (!in_array($sortFct, get_class_methods('Person')))
        {
            throw new Exception('People->sort(): Can\'t sort by ' . $attribute);
        }
        usort($this->people, 'Person::' . $sortFct);
    }
}

$people = new People;
$people->addPerson('Steve', 'M', 31);
$people->addPerson('John', 'M', 24);
$people->addPerson('Jane', 'F', 26);
$people->addPerson('Sally', 'F', 21);
$people->display();
$people->sort();
$people->display();
$people->sort('age');
$people->display();

答案 1 :(得分:4)

看看usort。它允许您指定自己的比较功能。每次需要比较两个对象时,它会调用您指定的比较函数,以查看哪个对象大于另一个(或者如果它们相等)。在比较函数中,您可以使用两个Person对象中的字段执行任何操作来比较它们。

要使用类方法进行回调(如示例所示),请查看passing callbacks。例如,你可以这样做:

class People {
    // your previously defined stuff here...

    public function sort() {
        usort($this->people, array($this, 'comparePeople'));
    }

    public function comparePeople(Person $p1, Person $p2) {
        return strcmp($p1->getName(), $p2->getName());
    }
}

您当然还需要在getName()课程中添加Person

对于静态方法,它可能看起来像这样:

function sortPeople($people) {
    usort($people, array('People', 'comparePeople'));
}

class People {
    // your previously defined stuff here...

    public static function comparePeople(Person $p1, Person $p2) {
        return strcmp($p1->getName(), $p2->getName());
    }
}

如您所见,它看起来非常相似。我不建议你使用静态方法。它更加混乱,违反了单一责任原则。

答案 2 :(得分:1)

特别是如果getName()是耗时的操作,那么使用 decorate-sort-undecorate 模式可能会更好。

<?php

class Person {
    private $name;
    function getName() {
      return $this->name;
    }
    function __construct($name) {
      $this->name = $name;
    }
}

$people = array(
    new Person('Jim'),
    new Person('Tom'),
    new Person('Tim'),
    new Person('Adam')
);

// actual sorting below
$people = array_map(create_function('$a', 'return array($a->getName(), $a);'), $people); // transform array of objects into array of arrays consisted of sort key and object
sort($people); // sort array of arrays
$people = array_map('end', $people); // take only last element from each array

print_r($people);

它是如何工作的?

不是对对象数组进行排序,而是对最后一个元素为object的数组进行排序,并且首先是要对其进行排序的键。排序后,您只保留对象。

您可以只使用sort对数组数组进行排序,因为PHP通过逐个比较其元素来比较两个相同长度的数组。

按多个字段排序

您可以使用多个排序键,例如按姓氏排序,如果姓氏相同,则考虑名字。您可以通过使用具有重要性顺序的多个键进行装饰来完成此操作:

$people = array_map(create_function('$a', 'return array($a->getSurname(), $a->getName(), $a);'), $people); 

为什么它很快

这种方式可能比使用usort更快,因为它只调用getName()n次来排序长度为n的数组。排序期间的比较是使用内置比较器完成的,因此应该很快。在usort方法中,自定义比较器在排序期间被多次调用(超过n次),这可能会减慢速度。