Passed
Push — master ( f509b3...5b74be )
by Eric
12:34 queued 10:26
created

Numbers::sizeFormat()   A

Complexity

Conditions 5
Paths 4

Size

Total Lines 28
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 14
CRAP Score 5

Importance

Changes 0
Metric Value
cc 5
eloc 12
nc 4
nop 3
dl 0
loc 28
ccs 14
cts 14
cp 1
crap 5
rs 9.5555
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
/**
6
 * Utility - Collection of various PHP utility functions.
7
 *
8
 * @author    Eric Sizemore <[email protected]>
9
 * @version   2.0.0
10
 * @copyright (C) 2017 - 2024 Eric Sizemore
11
 * @license   The MIT License (MIT)
12
 *
13
 * Copyright (C) 2017 - 2024 Eric Sizemore <https://www.secondversion.com>.
14
 *
15
 * Permission is hereby granted, free of charge, to any person obtaining a copy
16
 * of this software and associated documentation files (the "Software"), to
17
 * deal in the Software without restriction, including without limitation the
18
 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
19
 * sell copies of the Software, and to permit persons to whom the Software is
20
 * furnished to do so, subject to the following conditions:
21
 *
22
 * The above copyright notice and this permission notice shall be included in
23
 * all copies or substantial portions of the Software.
24
 *
25
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
26
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
27
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
28
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
29
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
30
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
31
 * THE SOFTWARE.
32
 */
33
34
namespace Esi\Utility;
35
36
// Exceptions
37
use Random\RandomException;
1 ignored issue
show
Bug introduced by
The type Random\RandomException was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
38
use ValueError;
39
use InvalidArgumentException;
40
41
// Functions
42
use function number_format;
43
use function abs;
44
use function random_int;
45
use function sprintf;
46
use function count;
47
48
/**
49
 * Number utilities.
50
 */
51
final class Numbers
52
{
53
    /**
54
     * Constants for Numbers::sizeFormat(). Sets bases and modifier for the conversion.
55
     *
56
     * @var int   BINARY_STANDARD_BASE
57
     * @var int   METRIC_STANDARD_BASE
58
     * @var float CONVERSION_MODIFIER
59
     */
60
    public const BINARY_STANDARD_BASE = 1024;
61
    public const METRIC_STANDARD_BASE = 1000;
62
    public const CONVERSION_MODIFIER = 0.9;
63
64
    /**
65
     * Ordinal suffixes.
66
     *
67
     * @var array<string> SUFFIXES
68
     */
69
    public const SUFFIXES = ['th', 'st', 'nd', 'rd'];
70
71
    /**
72
     * Standards units.
73
     *
74
     * @var array<string, array<string>> SIZE_FORMAT_UNITS
75
     */
76
    public const SIZE_FORMAT_UNITS = [
77
        'binary' => ['B', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB', 'YiB'],
78
        'metric' => ['B', 'kB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'],
79
    ];
80
81
    /**
82
     * inside()
83
     *
84
     * Determines if a number is inside the min and max.
85
     *
86
     * @param   float|int  $number  The number to check.
87
     * @param   float|int  $min     The minimum.
88
     * @param   float|int  $max     The maximum.
89
     * @return  bool
90
     */
91 2
    public static function inside(float | int $number, float | int $min, float | int $max): bool
92
    {
93 2
        return ($number >= $min && $number <= $max);
94
    }
95
96
    /**
97
     * outside()
98
     *
99
     * Determines if a number is outside the min and max.
100
     *
101
     * @param   float|int  $number  The number to check.
102
     * @param   float|int  $min     The minimum.
103
     * @param   float|int  $max     The maximum.
104
     * @return  bool
105
     */
106 2
    public static function outside(float | int $number, float | int $min, float | int $max): bool
107
    {
108 2
        return ($number < $min || $number > $max);
109
    }
110
111
    /**
112
     * random()
113
     *
114
     * Generate a cryptographically secure pseudo-random integer.
115
     *
116
     * @param   int<min, max>  $min  The lowest value to be returned, which must be PHP_INT_MIN or higher.
117
     * @param   int<min, max>  $max  The highest value to be returned, which must be less than or equal to PHP_INT_MAX.
118
     * @return  int<min, max>
119
     *
120
     * @throws RandomException | ValueError
121
     */
122 1
    public static function random(int $min, int $max): int
123
    {
124
        // Generate random int
125 1
        return random_int($min, $max);
126
    }
127
128
    /**
129
     * ordinal()
130
     *
131
     * Retrieve the ordinal version of a number.
132
     *
133
     * Basically, it will append th, st, nd, or rd based on what the number ends with.
134
     *
135
     * @param   int     $number  The number to create an ordinal version of.
136
     * @return  string
137
     */
138 1
    public static function ordinal(int $number): string
139
    {
140 1
        static $suffixes = self::SUFFIXES;
141
142 1
        $absNumber = abs($number);
143
144 1
        $suffix = $absNumber % 100 >= 11 && $absNumber % 100 <= 13 ? $suffixes[0] : $suffixes[$absNumber % 10] ?? $suffixes[0];
145 1
        return $number . $suffix;
146
    }
147
148
    /**
149
     * sizeFormat()
150
     *
151
     * Format bytes to a human-readable format.
152
     *
153
     * @param   int     $bytes      The number in bytes.
154
     * @param   int     $precision  Sets the number of decimal digits.
155
     * @param   string  $standard   Determines which mod ('base') to use in the conversion.
156
     * @return  string
157
     */
158 3
    public static function sizeFormat(int $bytes, int $precision = 0, string $standard = 'binary'): string
159
    {
160
        // The units/labels for each 'system'
161 3
        static $standards = [
162 3
            'binary' => ['base' => Numbers::BINARY_STANDARD_BASE, 'units' => self::SIZE_FORMAT_UNITS['binary']],
163 3
            'metric' => ['base' => Numbers::METRIC_STANDARD_BASE, 'units' => self::SIZE_FORMAT_UNITS['metric']],
164 3
        ];
165
166
        // Just a sanity check
167 3
        if (!isset($standards[$standard])) {
168 1
            throw new InvalidArgumentException('Invalid $standard specified, must be either metric or binary');
169
        }
170
171
        // Metric or Binary?
172 2
        $base = $standards[$standard]['base'];
173 2
        $units = $standards[$standard]['units'];
174
175
        // If $bytes is less than our base, there is no need for any conversion
176 2
        if ($bytes < $base) {
177 2
            return sprintf('%s %s', $bytes, $units[0]);
178
        }
179
180
        // Perform the conversion
181 2
        for ($i = 0; ($bytes / $base) > Numbers::CONVERSION_MODIFIER && ($i < count($units) - 1); $i++) {
182 2
            $bytes /= $base;
183
        }
184
        // @phpstan-ignore-next-line
185 2
        return number_format($bytes, $precision, '.', '') . ' ' . $units[$i];
186
    }
187
}
188