PHP ORDERBY function

Table of Contents

1 Description

This is a php function that sorts arrays of stuff using the ORDERBY syntax from SQL.

2 Usage

Here's a simple example:

$a = array(array("foo"=>8, "bar"=>2, "baz"=>2),
           array("foo"=>2, "bar"=>9, "baz"=>3),
           array("foo"=>8, "bar"=>1, "baz"=>4),
           array("foo"=>8, "bar"=>1, "baz"=>8),
           );
sql_sort($a, "foo, bar DESC, baz DESC");

This sorts the arrays in ascending order according the the "foo" key, and for all equal values given the "foo" key, sort it in descending order according to it's "bar" key and so forth. This is how it would sort it:

array(array("foo"=>2, "bar"=>9, "baz"=>3),
      array("foo"=>8, "bar"=>2, "baz"=>2),
      array("foo"=>8, "bar"=>1, "baz"=>8),
      array("foo"=>8, "bar"=>1, "baz"=>4));

But it also works for sorting lists of objects by field or method call, here's an example of that usage:

$a = array(new Foo(2, 4),
           new Foo(1, 2),
           new Foo(2, 9));
sql_sort($a, "foo, getBar() DESC");

This sorts by the field "foo" and the method "getBar".

3 Talk

This basically works by making a compare function for use with usort(). The compare function is as you would expect just with another compare function embedded if values are equal. Here is the compare function

for "foo, getBar() DESC":
$x = $a->{"foo"};
$y = $b->{"foo"};
if ($x == $y) {
  $x = call_user_method("getBar", $a); 
  $y = call_user_method("getBar", $b); 
  if ($x == $y) 
    return 0;
  return $x > $y ? -1 : 1;
 }
return $x < $y ? -1 : 1;

If there had been a third clause another code block would have been inserted instead of "return 0;"

4 Code

download

<?php

function sql_sort(&$array, $orderby_clause) {
  if (!is_array($array))
    trigger_error("sql_sort: first parameter isn't an array.", E_USER_ERROR);
  if (!is_array($array[0]) && !is_object($array[0]))
    trigger_error("sql_sort: first parameter isn't an array ".
                  "consisting of arrays of objects.", E_USER_ERROR);

  $orderby_clauses = explode(",", 
                           preg_replace("/[\s\n]+/ms", " ", $orderby_clause));
  $orderby = array();
  foreach($orderby_clauses as $orderby_clause) {
    list($name, $type) = explode(" ", trim($orderby_clause));
    $type = (strtoupper($type) == "DESC") ? "DESC" : "ASC";

    if (substr($name, -2) == "()") {
      $array_type = "method";
      if (!method_exists($array[0], substr($name,0,-2)))
        trigger_error("sql_sort: method '$name' not found.", E_USER_ERROR);
    } else {
      if (is_array($array[0])) {
        $array_type = "key";
        if (!isset($array[0][$name]))
          trigger_error("sql_sort: key '$name' not found.", E_USER_ERROR);
      }else {
        $array_type = "field";
        if (!isset($array[0]->{$name}))
          trigger_error("sql_sort: field '$name' not found.", E_USER_ERROR);
      }
    }

    $orderby[] = array($name, $type, $array_type);
  }

  $cmp_func = create_function('$a,$b', 
                              sql_sort_cmp_bulider($orderby));
  usort($array, $cmp_func);
}
function sql_sort_cmp_bulider($orderby_clauses) {
  $cmp_func = "";
  list($name, $type, $array_type) = array_shift($orderby_clauses);

  if ($array_type == "method") {
    $name = substr($name, 0, -2);
    $cmp_func .= '$x = call_user_method("'.$name.'", $a); '."\n".
      '$y = call_user_method("'.$name.'", $b); '."\n";
  } elseif ($array_type == "key") {
      $cmp_func .= '$x = $a["'.$name.'"];'."\n".
        '$y = $b["'.$name.'"];'."\n";
  } elseif ($array_type == "field") {
    $cmp_func .= '$x = $a->{"'.$name.'"};'."\n".
      '$y = $b->{"'.$name.'"};'."\n";
  }

  if (count($orderby_clauses) > 0) {
    $cmp_func .= 'if ($x == $y) {'."\n".
      sql_sort_cmp_bulider($orderby_clauses)."}\n";
  } else {
    $cmp_func .= 'if ($x == $y) '."\n".
      "return 0;\n";
  }

  if ($type == "ASC") {
    $cmp_func .= 'return $x < $y ? -1 : 1;'."\n";
  } else {
    $cmp_func .= 'return $x > $y ? -1 : 1;'."\n";
  }
  return $cmp_func;
}

Author: Dan Amlund Thomsen

Created: 2019-05-09 Thu 19:53

Validate