Пока оптимизировал имеющееся решение. если лучше никто не предложит, то может кому пригодится.
Сервисная часть:
<?php
function moveArrayItem($key, &$from, &$to)
{
$to[$key] = &$from[$key];
unset($from[$key]);
}
function moveArraySlice(&$array, $what, $after, $whatCond = null, $afterCond = null)
{
$result = array();
$tmp = array();
$trigger = false;
foreach ($array as $key => $item)
{
$found =
(!empty($whatCond) && $whatCond($key, $item, $what, $after)) ||
(empty($whatCond) && $key == $what);
$trigger = $trigger || $found;
if ($trigger && !$found)
break;
elseif ($found)
moveArrayItem($key, $array, $tmp);
}
if ($after !== null)
{
$trigger = false;
foreach ($array as $key => $item)
{
$found =
(!empty($afterCond) && $afterCond($key, $item, $what, $after)) ||
(empty($afterCond) && $key == $after);
$trigger = $trigger || $found;
if ($trigger && !$found)
break;
moveArrayItem($key, $array, $result);
}
}
foreach (array_keys($tmp) as $key)
moveArrayItem($key, $tmp, $result);
foreach (array_keys($array) as $key)
moveArrayItem($key, $array, $result);
foreach (array_keys($result) as $key)
moveArrayItem($key, $result, $array);
}
?>
Тестовая часть:
<?php
$what = 8;
$after = 0;
$src = array(
"1" => array('id' => 1, 'parent' => 0),
"3" => array('id' => 3, 'parent' => 1),
"4" => array('id' => 4, 'parent' => 1),
"6" => array('id' => 6, 'parent' => 0),
"7" => array('id' => 7, 'parent' => 6),
"8" => array('id' => 8, 'parent' => 0),
"9" => array('id' => 9, 'parent' => 8),
);
moveArraySlice(
$src,
$what,
$after ? $after : null,
$src[$what]['parent'] ? null : create_function('$k, &$v, $w, $a', 'return $k == $w || $v["parent"] == $w;'),
$src[$what]['parent'] ? null : create_function('$k, &$v, $w, $a', 'return $k == $a || $v["parent"] == $a);')
);
print_r($src);
?>
Функция moveArraySlice() переносит либо элемент с ключом $what и помещает его после элемента с ключом $after.
Альтернативно можно указать $cbWhatCond и/или $cbAfterCond.
Условие $cbWhatCond задает срез из последовательных элементов для переноса.
Условие $cbAfterCond задает срез, за которым следует разместить.
Позиция начала списка - null.