Chcąc dostosować swój kod do wersji PHP 5.3, tak aby wykonywał się bezproblemowo z uwzględnieniem błędów STRICT natrafiłem na taki drobny szczegół. Swego czasu dodałem do manuala funkcji array_multisort na php.net taką drobną [notkę zawierającą implementację funkcji ułatwiającej sortowanie wyników zapytań sql-owych] (http://usphp.com/manual/en/function.array-multisort.php#87268).
Chcąc ją dzisiaj użyć dostałem na twarz warning-a „Parameter 2 to array_multisort() expected to be a reference, value given”.
Załóżmy, że miałem następujące dane.
$data = array( 0 => array ( 'id' => '1', 'name' => 'Rodzaje', ), 1 => array ( 'id' => '2', 'name' => 'Kategorie', ), 2 => array ( 'id' => '3', 'name' => 'Statusy', ), 3 => array ( 'id' => '4', 'name' => 'Kolory', ), ); |
Aby posortować tę tablicę według kolumny „name” wywołałem wspomnianą funkcję w następujący sposób
sortDbResult($data, 'name', SORT_ASC, SORT_STRING); |
Przyjrzałem się problematycznej linii i zobaczyłem, że wywołuję funkcję array_multisort przy pomocy funkcji call_user_func_array, do której parametry przekazuję za pośrednictwem tablicy.
call_user_func_array('array_multisort', $_params); |
W moim przypadku zmienna $_params miała następującą zawartość
array( 0 => &array ( 0 => 'Rodzaje', 1 => 'Kategorie', 2 => 'Statusy', 3 => 'Kolory', ), 1 => 2, 2 => 4, 3 => array( 0 => array ( 'id' => '1', 'name' => 'Rodzaje', ), 1 => array ( 'id' => '2', 'name' => 'Kategorie', ), 2 => array ( 'id' => '3', 'name' => 'Statusy', ), 3 => array ( 'id' => '4', 'name' => 'Kolory', ), )); |
Pomyślałem sobie o co chodzi z tym błędem w końcu drugi parametr funkcji array_multisort to w moim przypadku wartość stałej SORT_ASC czyli 2. Przeprowadziłem mały eksperyment i wywołałem funkcję array_multisort bezpośrednio.
$data_1 = array ( 0 => 'Rodzaje', 1 => 'Kategorie', 2 => 'Statusy', 3 => 'Kolory', ); $data_2 = array( 0 => array ( 'id' => '1', 'name' => 'Rodzaje', ), 1 => array ( 'id' => '2', 'name' => 'Kategorie', ), 2 => array ( 'id' => '3', 'name' => 'Statusy', ), 3 => array ( 'id' => '4', 'name' => 'Kolory', ), ); array_multisort($data_1, SORT_ASC, SORT_STRING, $data_2); var_dump($data_2); |
Zadziałało. Tablica $_data2 została posortowana prawidłowo.
call_user_func_array('array_multisort', array(&$data_1, SORT_ASC, SORT_STRING, &$data_2)); |
Powyższy kod również wykonał się nie zwracając żadnych komunikatów błędów.
$params = array(&$data_1, SORT_ASC, SORT_STRING, &$data_2); call_user_func_array('array_multisort', $params); |
Wykonanie powyższego kodu kończy się już niestety warningiem. Aby się go pozbyć trzeba użyć małego obejścia i przypisać wartości stałych do zmiennych a następnie przekazać je do tablicy przy pomocy referencji.
$o = SORT_ASC; $v = SORT_STRING; $params = array(&$data_1, &$o, &$v, &$data_2); call_user_func_array('array_multisort', $params); |
W tym wypadku nie działa ukrywanie błędów. Funkcja array_multisort po prostu nie zadziała prawidłowo.
Poprawiona funkcja sortDbResult wygląda następująco:
/**
* Sort DB result
*
* @param array $data Result of sql query as associative array
*
* Rest of parameters are optional
* [, string $name [, mixed $name or $order [, mixed $name or $mode]]]
* $name string - column name i database table
* $order integer - sorting direction ascending (SORT_ASC) or descending (SORT_DESC)
* $mode integer - sorting mode (SORT_REGULAR, SORT_STRING, SORT_NUMERIC)
*
*
* $i,
* 'first_name' => sprintf('first_name_%s', rand(1, 9)),
* 'last_name' => sprintf('last_name_%s', rand(1, 9)),
* 'date' => date('Y-m-d', rand(0, time()))
* );
* }
* $data = sortDbResult($data, 'date', SORT_DESC, SORT_NUMERIC, 'id');
* var_dump($data);
* $data = sortDbResult($data, 'last_name', SORT_ASC, SORT_STRING, 'first_name', SORT_ASC, SORT_STRING);
* var_dump($data);
* ?>
*
*
* @return array $data - Sorted data
*/
function sortDbResult(array $data /*$name, $order, $mode*/) { $_argList = func_get_args(); $_data = array_shift($_argList); if (empty($_data)) { return $_data; } $_max = count($_argList); $_params = array(); $_cols = array(); $_rules = array(); for ($_i = 0; $_i < $_max; $_i += 3) { $_name = (string) $_argList[$_i]; if (!in_array($_name, array_keys(current($_data)))) { continue; } if (!isset($_argList[($_i + 1)]) || is_string($_argList[($_i + 1)])) { $_order = SORT_ASC; $_mode = SORT_REGULAR; $_i -= 2; } else if (3 > $_argList[($_i + 1)]) { $_order = SORT_ASC; $_mode = $_argList[($_i + 1)]; $_i--; } else { $_order = $_argList[($_i + 1)] == SORT_ASC ? SORT_ASC : SORT_DESC; if (!isset($_argList[($_i + 2)]) || is_string($_argList[($_i + 2)])) { $_mode = SORT_REGULAR; $_i--; } else { $_mode = $_argList[($_i + 2)]; } } $_mode = $_mode != SORT_NUMERIC ? $_argList[($_i + 2)] != SORT_STRING ? SORT_REGULAR : SORT_STRING : SORT_NUMERIC; // references below required from PHP 5.3 $_rules[] = array('name' => $_name, 'order' => &$_order, 'mode' => &$_mode); } foreach ($_data as $_k => $_row) { foreach ($_rules as $_rule) { if (!isset($_cols[$_rule['name']])) { $_cols[$_rule['name']] = array(); $_params[] = &$_cols[$_rule['name']]; // references below required from PHP 5.3 $_params[] = &$_rule['order']; $_params[] = &$_rule['mode']; } $_cols[$_rule['name']][$_k] = $_row[$_rule['name']]; } } $_params[] = &$_data; call_user_func_array('array_multisort', $_params); return $_data; } |