Comparators

Comparators are used to determine the order of objects in Arrays::sort. It is a flexible mechanism to compare objects. Ouzo provides various comparators out of the box and the ability to write your custom comparators.

Comparator class is a facade which contains all comparators: * natural * reverse * compareBy * compound

Natural order

As simple as it gets:

$result = Arrays::sort([1, 3, 2], Comparator::natural());

It sorts given array in a natural order, so the result would be 1, 2, 3.

Reverse

It is a comparator according to which order of elements is reversed. It expects another comparator as a parameter. E.g.

$result = Arrays::sort([1, 3, 2], Comparator::reverse(Comparator::natural()));

Result is obviously a reversed array of natural order, which is 3, 2, 1. Any comparator may be passed as a parameter. Combining comparators? Just imagine the possibilities!

Compare by

Compares objects by using values computed using given expressions. Expressions should comply with format accepted by Functions::extractExpression.

Imagine you have Product and you want to sort it by its name property. Not a problem:

$product1 = new Product(['name' => 'b']);
$product2 = new Product(['name' => 'c']);
$product3 = new Product(['name' => 'a']);

$result = Arrays::sort([$product1, $product2, $product3], Comparator::compareBy('name'));

In case you haven’t heard of Ouzo’s assertions, here is the simplest way to test if the above is true:

$result = Assert::thatArray($result)->onProperty('name')->containsExactly('a', 'b', 'c');

You can specify as many expressions as you need, e.g.

Comparator::compareBy('name', 'description', 'price');

Compound

Combines comparators into one, ordered by first comparator. If two values are equal according to the first comparator (tie), then tie breakers resolve conflicts. Second provided comparator is the first tie breaker, third is the second tie breaker and so on.

Example:

$product1 = new Product(['name' => 'a', 'description' => '2']);
$product2 = new Product(['name' => 'b', 'description' => '2']);
$product3 = new Product(['name' => 'a', 'description' => '1']);

$result = Arrays::sort([$product1, $product2, $product3],
    Comparator::compound(
        Comparator::reverse(Comparator::compareBy('name')),
        Comparator::compareBy('description')
    )
);
Now, let’s analyze it:
  1. products are sorted by name property (a, a, b)
  2. reversed (b, a, a)
  3. there is a conflict (a = a)
  4. so a tie breaker goes to work
  5. ties are sorted by description property (b, a1, a2)

Voila!

Custom comparators

If you want to write your own comparator the only thing you need to do is to create a class with __invoke method implemented.

Comparator returns an integer less than, equal to, or greater than zero if the first argument is considered to be respectively less than, equal to, or greater than the second.

Take a look at Ouzo\Utilities\Comparator classes for more details.