public static function byBubbleCallback($list, $callback = false)
    {
        $size = count($list);
        $sortedList = $list;

        if ($size > 0) {
            $normalizedList = [];
            // normalize list
            foreach ($list as $item) {
                $normalizedList[] = $item;
            }
            // optimized bubble sort
            while ($size > 0) {
                $newSize = 0;
                for ($i = 1; $i <= $size-1; $i++) {
                    // compare: a > b using callback
                    if ($callback) {
                        $swap = call_user_func_array($callback, ['a' => $normalizedList[$i-1], 'b' => $normalizedList[$i]]);
                    } else {
                        $swap = $normalizedList[$i-1] > $normalizedList[$i];
                    }
                    if ($swap) {
                        $itemA = $normalizedList[$i-1];
                        $itemB = $normalizedList[$i];
                        $normalizedList[$i-1] = $itemB;
                        $normalizedList[$i] = $itemA;
                        // swap
                        $newSize = $i;
                    }
                }
                $size = $newSize;
            }

            $sortedList = $normalizedList;
        }

        return $sortedList;
    }