Неправильно используемый array_multisort(), дающий правильный результат?
В настоящее время я касаюсь какого-то устаревшего кода в попытке очистить его и натолкнулся на что-то вроде загадки. Я не решаю даже отдаленно критически важную задачу, поэтому считаю, что это, по большей части, спортивный вопрос, но он все еще вызывает недоумение. Цвет мне любопытен.
Этот код:
// dummy data for the sake of testing / abstract visualisation;
// x is thrown in as an experiment:
$workTables = array(
array('x' => 5, 'Name' => 'foo3', 'Update_time' => '2013-04-04 04:40',),
array('x' => 4, 'Name' => 'foo4', 'Update_time' => '2013-04-01 04:40',),
array('x' => 3, 'Name' => 'foo2', 'Update_time' => '2013-04-04 09:40',),
array('x' => 2, 'Name' => 'foo1', 'Update_time' => '2013-04-12 04:40',),
array('x' => 1, 'Name' => 'foo5', 'Update_time' => '2012-12-04 04:40',),
);
// original legacy code:
if (!empty($workTables)) {
$sort = array();
foreach ($workTables as $key => $value) {
$sort[$key]["Update_time"] = $value["Update_time"];
}
array_multisort($workTables, SORT_ASC, SORT_STRING, $sort);
}
... при этом бросая двенадцать уведомлений (" Notice: Array to string conversion ...
"), работает как положено, упорядочив все элементы в $workTables
в соответствии с Update_time
,
(Столбец "х" является частью моей попытки исключить, что он имеет какое-либо отношение к Name
, который в исходном коде является фиксированным префиксом, за которым следует отметка времени (например, work_table_1367940392
, work_table_1367940395
...), делая сортировку по Name
эквивалентно сортировке по Update_time
.)
Очевидно, так как я не хочу программировать по совпадению, по крайней мере это будет заменено на:
// new code:
if (!empty($workTables)) {
$sort = array();
foreach ($workTables as $key => $value) {
$sort[$key] = $value["Update_time"];
}
array_multisort($sort, SORT_ASC, SORT_STRING, $workTables);
}
... что соответствует описанию array_multisort()
также делает то, что мы хотим, и не бросает уведомления в наше лицо.
Но что меня действительно интересует, так это почему старый код работает (несмотря на это).
Частичной причиной, по-видимому, является поведение asort()
и со., которые имеют (частично) недокументированную особенность, что они могут работать с многомерными массивами, действуя в соответствии с содержимым массива, работая через структуру "слева направо" (по крайней мере, в PHP 5.4.7 (cli)
)... но... я застрял, пытаясь понять, что делает $workTables
а также $sort
" взаимозаменяемы ".
Я пытался взглянуть на исходный код PHP на C, чтобы понять это, но я застрял в попытке понять, что здесь происходит:
/* Do the actual sort magic - bada-bim, bada-boom. */
zend_qsort(indirect, array_size, sizeof(Bucket **), php_multisort_compare TSRMLS_CC);
... так как мои знания C ужасно заржавели и zend_qsort()
Сам по себе просто из моей лиги.
Любой берущий?
Имейте в виду, я не отчаянно нуждаюсь в ответе, так что не тратьте слишком много времени на это, но, возможно, кому-то тоже нравится головоломка?:)
Лично я потратил некоторое время на это исключительно потому, что предпочитаю тщательно разбираться в коде, особенно когда пытаюсь его очистить - даже если он работает только по стечению обстоятельств. Я только что зашел в тупик, когда дело доходит до дальнейшего понимания, так что переполнение стека кажется лучшим шансом для дальнейшего просвещения.
Итак, если у вас есть представление о том, что происходит за кулисами (я подозреваю, что это что-то тривиальное, что я упустил из виду; как правило, это моя проблема после того, как я некоторое время хожу по кругу), я хотел бы услышать это!:)
1 ответ
Насколько я понимаю, массив создается и хранится в $sort[$key]
, Затем, как только вы позвоните array_multisort()
бывает так, что массив преобразуется обратно в строку и сортируется с использованием этой строки в качестве значения, определяющего порядок - как сказано в предупреждении. Затем эта строка используется в качестве значения, определяющего порядок.
Как выполняется преобразование массива-> строка? Просто делаю echo $anArrayValueHere;
не полезно; распечатывает Array
, Подобный трюк, echo "" . $anArrayValueHere . "";
также не дает ничего полезного. (Но при этом это не приводит к уведомлению!)
Вполне возможно, что serialize()
используется. Исходя из этого, давайте посмотрим, что будет использоваться в качестве значения, определяющего порядок:
#!/usr/bin/php5
<?php
$sort[0]["Update_time"] = '2012-12-04 04:40';
echo serialize($sort[0]);
затем
$ ./php tmp.php
a:1:{s:11:"Update_time";s:16:"2012-12-04 04:40";}
Похоже, что ключ был бы достаточно определенным, чтобы дать что-то полезное для определения порядка сортировки так же, как и просто Update_time
значение будет.
Я не уверен что serialize()
используется, но если это так, я думаю, что это объяснение.