Функция cot_build_friendlynumber в Cotonti

Функция cot_build_friendlynumber предназначена для генерации удобочитаемого числа с локализованными единицами измерения.

Код функции


/**
 * Generic function for generating a human-readable number with localized units.
 *
 * @param float $number
 *    Input number to convert, based on the unit with size (key) 1.
 * @param array $units
 *    Array of units as $relativesize => $unit.
 *  Example: array('3600' => 'hours', '60' => 'minutes', '1' => 'seconds').
 *    Where 'seconds' is the base unit, since it has a value of 1. Hours has a value of
 *    3600, since one hour contains 3600 seconds. Values can be given as strings or integers.
 * @param int $levels
 *    Number of levels to return.
 *    "3 hours 45 minutes" = 2 levels.
 * @param int $decimals
 *    Number of decimals to show in last level.
 *    "2 minutes 20.5 seconds" = 2 levels, 1 decimals.
 * @param mixed $round
 *    Number of decimals to round the last level up to, can also be negative, see round().
 *    Set false to disable or null to inherit from $decimals.
 * @param string $smallestunit
 *  Key of the smallest unit to show. Any number smaller than this will return 'Less than 1 ...'.
 *  Effectively its a way to cut off $units at a certain key.
 * @return string
 */
function cot_build_friendlynumber($number, $units, $levels = 1, $decimals = 0, $round = null, $smallestunit = null)
{
    global $L;
    if (!is_array($units)) return '';
    $pieces = array();

    // First sort from big to small
    ksort($units, SORT_NUMERIC);
    $units = array_reverse($units, true);

    // Trim units after $smallestunit
    if (array_key_exists($smallestunit, $units))
    {
        $offset = array_search($smallestunit, array_keys($units));
        $units = array_slice($units, 0, $offset+1, true);
    }

    if ($number == 0)
    {
        // Return smallest possible unit
        $units = array_reverse(array_values($units));
        return cot_declension(0, $units[0]);
    }

    foreach ($units as $size => $expr)
    {
        $size = floatval($size);
        if ($number >= $size)
        {
            $levels--;
            $num = $number / $size;
            $number -= floor($num) * $size;
            if ($number > 0 && $levels > 0)
            {
                // There's more to come, so no decimals yet.
                $pieces[] = cot_declension(floor($num), $expr);
            }
            else
            {
                // Last item gets decimals and rounding.
                if($decimals > 0)
                {
                    $pieces[] = cot_build_number($num, $decimals, $round). ' ' .
                    cot_declension($num, $expr, true, true);
                }
                else
                {
                    $pieces[] = floor($num). ' ' .
                    cot_declension(floor($num), $expr, true, true);
                }
                break;
            }
            if ($levels == 0)
            {
                break;
            }
        }
    }
    if (count($pieces) == 0)
    {
        // Smaller than smallest possible unit
        $expr = array_reverse(array_values($units));
        return $L['LessThan'] . ' ' . cot_declension(1, $expr[0]);
    }
    return implode(' ', $pieces);
}

Подробное описание:
Параметры функции:

$number: Число для конвертации, основанное на единице измерения с размером (ключ) 1.
$units: Массив единиц измерения, где ключ - относительный размер единицы, а значение - название единицы. Пример: array('3600' => 'hours', '60' => 'minutes', '1' => 'seconds').
$levels: Количество уровней для возврата. Например, "3 hours 45 minutes" = 2 уровня.
$decimals: Количество десятичных знаков для отображения на последнем уровне.
$round: Количество десятичных знаков для округления последнего уровня. Может быть отрицательным, как в функции round(). Можно отключить, установив значение false, или наследовать от $decimals, установив null.
$smallestunit: Ключ самой маленькой единицы, которую нужно показывать. Число, меньшее этого значения, вернёт "Меньше 1 ...".
Описание работы:

Сначала единицы измерения сортируются от большего к меньшему.
Если указан параметр $smallestunit, массив единиц обрезается до этой единицы.
Если переданное число равно нулю, возвращается самая маленькая возможная единица с количеством 0.
Перебираются единицы измерения и для каждой рассчитывается количество полных единиц в переданном числе.
Последняя единица получает десятичные знаки и округление.
Если количество уровней равно нулю, цикл прерывается.
Если число меньше самой маленькой единицы, возвращается строка "Меньше 1 ..." с указанием единицы.

Пример общего использования:


$units = array(
    '3600' => 'hours',
    '60' => 'minutes',
    '1' => 'seconds'
);
echo cot_build_friendlynumber(3670, $units, 2, 1); // Выводит "1 hour 1 minute"


Этот пример выводит удобочитаемую строку "1 hour 1 minute" для числа 3670, что эквивалентно 1 часу и 1 минуте.

Разберём функцию cot_build_friendlynumber по условиям.

Условия в функции:
Проверка, что $units - массив:

if (!is_array($units)) return '';

Если $units не является массивом, функция возвращает пустую строку.


Сортировка единиц измерения:

ksort($units, SORT_NUMERIC);
$units = array_reverse($units, true);

Сначала массив единиц измерения сортируется по ключам (размеру) в порядке возрастания, затем переворачивается, чтобы идти от больших единиц к меньшим.


Обрезка массива единиц после $smallestunit:

if (array_key_exists($smallestunit, $units))
{
    $offset = array_search($smallestunit, array_keys($units));
    $units = array_slice($units, 0, $offset+1, true);
}


Если ключ $smallestunit существует в массиве $units, массив обрезается до этой единицы включительно.
Обработка нулевого значения:

if ($number == 0)
{
    // Возвращается самая маленькая возможная единица с количеством 0
    $units = array_reverse(array_values($units));
    return cot_declension(0, $units[0]);
}

Если переданное число равно нулю, возвращается строка с самой маленькой единицей и количеством 0.
Цикл по единицам измерения:

foreach ($units as $size => $expr)
Для каждой единицы измерения проверяется, сколько раз она помещается в переданном числе.

Расчёт количества полных единиц:

$num = $number / $size;
$number -= floor($num) * $size;


Расчёт количества полных единиц, вычитание этого количества из общего числа.
Добавление уровня с десятичными знаками:

if($decimals > 0)
{
    $pieces[] = cot_build_number($num, $decimals, $round) . ' ' . cot_declension($num, $expr, true, true);
}
else
{
    $pieces[] = floor($num) . ' ' . cot_declension(floor($num), $expr, true, true);
}


Если указано количество десятичных знаков, оно используется при добавлении уровня, иначе используется целое число.
Обработка оставшихся уровней:


if ($levels == 0)
{
    break;
}

Если достигнуто заданное количество уровней, цикл прерывается.
Меньше самой маленькой единицы:


if (count($pieces) == 0)
{
    // Меньше самой маленькой возможной единицы
    $expr = array_reverse(array_values($units));
    return $L['LessThan'] . ' ' . cot_declension(1, $expr[0]);
}


Если число меньше самой маленькой единицы, возвращается строка "Меньше 1 ..." с этой единицей.


Генерация удобочитаемого числа с локализованными единицами:

Массив единиц измерения:

* Массив единиц измерения в формате $relativesize => $unit.
* Пример: array('3600' => 'часов', '60' => 'минут', '1' => 'секунд').

Количество уровней для возврата:

* Количество уровней для возврата. Например, "3 часа 45 минут" = 2 уровня.


Количество десятичных знаков на последнем уровне:

* Количество десятичных знаков на последнем уровне. Например, "2 минуты 20,5 секунд" = 2 уровня, 1 десятичный знак.


Округление последнего уровня:

* Округление последнего уровня до указанного количества десятичных знаков. Можно использовать отрицательные значения, как в функции round().


Ключ самой маленькой единицы для отображения:

* Ключ самой маленькой единицы для отображения. Любое число меньше этого значения вернёт "Меньше 1 ...".
Этот подробный разбор и перевод комментариев помогут лучше понять логику работы функции в контексте Cotonti.

6 минут чтения Administrator

Комментарии (0)

Комментарии отсутствуют
Добавление комментариев доступно только зарегистрированным пользователям

Автор контента

Administrator

Оффлайн

Administrator

Последняя авторизация: 05.07.2026 18:32

  • Страница размещена: 21.01.2025 22:57
  • Последнее обновление: 21.01.2025 22:57