Test Failed
Push — master ( be437e...866f6c )
by Julien
07:25
created

mb_vsprintf()   C

Complexity

Conditions 13
Paths 44

Size

Total Lines 86
Code Lines 50

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 46
CRAP Score 13.0864

Importance

Changes 3
Bugs 1 Features 0
Metric Value
cc 13
eloc 50
c 3
b 1
f 0
nc 44
nop 3
dl 0
loc 86
ccs 46
cts 50
cp 0.92
crap 13.0864
rs 6.6166

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
/**
4
 * This file is part of the Zemit Framework.
5
 *
6
 * (c) Zemit Team <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE.txt
9
 * file that was distributed with this source code.
10
 */
11
12
if (!function_exists('implode_sprintf')) {
13
    /**
14
     * Will implode an array_map return of the sprintf or mb_sprintf results
15
     */
16
    function implode_sprintf(array $array = [], string $glue = ' ', string $format = '%s', $multibyte = false, ?string $encoding = null): string
17
    {
18
        // Filter out null values from the array
19 20
        $array = array_filter($array, function ($value) {
20 18
            return $value !== null;
21 20
        });
22
        
23 20
        return implode($glue, array_map(function ($value, $key) use ($format, $multibyte, $encoding) {
24 18
            return $multibyte
25 9
                ? mb_vsprintf($format, [$value, $key], $encoding)
26 18
                : sprintf($format, $value, $key);
27 20
        }, $array, array_keys($array)));
28
    }
29
}
30
31
if (!function_exists('implode_mb_sprintf')) {
32
    /**
33
     * Will implode an array_map return of the mb_sprintf results
34
     */
35
    function implode_mb_sprintf(array $array = [], string $glue = ' ', string $format = '%s', ?string $encoding = null): string
36
    {
37 10
        return implode_sprintf($array, $glue, $format, true, $encoding);
38
    }
39
}
40
41
if (!function_exists('sprintfn')) {
42
    /**
43
     * version of sprintf for cases where named arguments are desired (php syntax)
44
     *
45
     * with sprintf: sprintf('second: %2$s ; first: %1$s', '1st', '2nd');
46
     *
47
     * with sprintfn: sprintfn('second: %second$s ; first: %first$s', array(
48
     *  'first' => '1st',
49
     *  'second'=> '2nd'
50
     * ));
51
     *
52
     * @param string $format sprintf format string, with any number of named arguments
53
     * @param array $args array of [ 'arg_name' => 'arg value', ... ] replacements to be made
54
     * @return string|false result of sprintf call, or bool false on error
55
     */
56
    function sprintfn(string $format, array $args = []): false|string
57
    {
58
        // map of argument names to their corresponding sprintf numeric argument value
59 10
        $array = array_keys($args);
60 10
        array_unshift($array, 0);
61 10
        $array = array_flip(array_slice($array, 1, null, true));
62
        
63
        // find the next named argument. each search starts at the end of the previous replacement.
64 10
        for ($pos = 0; preg_match('/(?<=%)([a-zA-Z_]\w*)(?=\$)/', $format, $match, PREG_OFFSET_CAPTURE, $pos);) {
65 8
            $position = intval($match[0][1]);
66 8
            $length = strlen($match[0][0]);
67 8
            $key = $match[1][0];
68
            
69
            // programmer did not supply a value for the named argument found in the format string
70 8
            if (!array_key_exists($key, $array)) {
71 2
                user_error("sprintfn(): Missing argument '{${$key}}'", E_USER_WARNING);
72
                return false;
73
            }
74
            
75
            // replace the named argument with the corresponding numeric one
76 8
            $replace = (string)$array[$key];
77 8
            $format = (string)substr_replace($format, $replace, $position, $length);
78 8
            $pos = $position + strlen($replace);
79
            
80
            // skip to end of replacement for next iteration
81
        }
82
        
83 8
        return vsprintf($format, array_values($args));
84
    }
85
}
86
87
if (!function_exists('mb_sprintf')) {
88
    /**
89
     * Return a formatted multibyte string
90
     * A more complete and working version of mb_sprintf and mb_vsprintf.
91
     * It should work with any "ASCII preserving" encoding such as UTF-8 and all the ISO-8859 charsets.
92
     * It handles sign, padding, alignment, width and precision. Argument swapping is not handled.
93
     */
94
    function mb_sprintf(string $format, ...$args): string
95
    {
96 11
        return mb_vsprintf($format, $args);
97
    }
98
}
99
100
if (!function_exists('mb_vsprintf')) {
101
    /**
102
     * Return a formatted string
103
     * It should work with any "ASCII preserving" encoding such as UTF-8 and all the ISO-8859 charsets.
104
     * It handles sign, padding, alignment, width and precision. Argument swapping is not handled.
105
     * Works with all encodings in format and arguments.
106
     * Supported: Sign, padding, alignment, width and precision.
107
     * Not supported: Argument swapping.
108
     *
109
     * @author Viktor Söderqvist <[email protected]>
110
     * @link http://php.net/manual/en/function.sprintf.php#89020
111
     */
112
    function mb_vsprintf(string $format, array $argv, ?string $encoding = null)
113
    {
114 31
        if (is_null($encoding)) {
115 31
            $encoding = strval(mb_internal_encoding());
116
        }
117
        
118
        // Use UTF-8 in the format so we can use the u flag in preg_split
119 31
        $format = strval(mb_convert_encoding($format, 'UTF-8', $encoding));
120
        
121 31
        $newFormat = ''; // build a new format in UTF-8
122 31
        $newArgv = []; // unhandled args in unchanged encoding
123
        
124 31
        while ($format !== '') {
125
            
126
            // Split the format in two parts: $pre and $post by the first %-directive
127
            // We get also the matched groups
128 29
            $pregSplitResult =
129 29
                preg_split(
130 29
                    "!%(\+?)('.|[0 ]|)(-?)([1-9][0-9]*|)(\.[1-9][0-9]*|)([%a-zA-Z])!u",
131 29
                    $format,
132 29
                    2,
133 29
                    PREG_SPLIT_DELIM_CAPTURE
134 29
                );
135
            
136 29
            $pre = $pregSplitResult[0] ?? '';
137 29
            $sign = $pregSplitResult[1] ?? '';
138 29
            $filler = $pregSplitResult[2] ?? '';
139 29
            $align = $pregSplitResult[3] ?? '';
140 29
            $size = $pregSplitResult[4] ?? '';
141 29
            $precision = $pregSplitResult[5] ?? '';
142 29
            $type = $pregSplitResult[6] ?? '';
143 29
            $post = $pregSplitResult[7] ?? '';
144
            
145 29
            $newFormat .= mb_convert_encoding($pre, $encoding, 'UTF-8');
146
            
147 29
            if ($type == '') {
148
                // didn't match. do nothing. this is the last iteration.
149
            }
150 29
            else if ($type == '%') {
151
                // an escaped %
152
                $newFormat .= '%%';
153
            }
154 29
            else if ($type == 's') {
155 26
                $arg = array_shift($argv);
156 26
                $arg = mb_convert_encoding($arg, 'UTF-8', $encoding);
157 26
                assert(is_string($arg));
158 26
                $padding_pre = '';
159 26
                $padding_post = '';
160
                
161
                // truncate $arg
162 26
                if ($precision !== '') {
163
                    $precision = intval(substr($precision, 1));
164
                    if ($precision > 0 && mb_strlen($arg, $encoding) > $precision) {
165
                        $arg = mb_substr(strval($precision), 0, $precision, $encoding);
166
                    }
167
                }
168
                
169
                // define padding
170 26
                $size = (int)$size;
171 26
                if ($size > 0) {
172 4
                    $argLength = mb_strlen($arg, $encoding);
173 4
                    if ($argLength < $size) {
174 4
                        if ($filler === '') {
175 4
                            $filler = ' ';
176
                        }
177 4
                        if ($align == '-') {
178 2
                            $padding_post = str_repeat($filler, $size - $argLength);
179
                        } else {
180 2
                            $padding_pre = str_repeat($filler, $size - $argLength);
181
                        }
182
                    }
183
                }
184
                
185
                // escape % and pass it forward
186 26
                $newFormat .= $padding_pre . str_replace('%', '%%', $arg) . $padding_post;
187
            }
188
            else {
189
                // another type, pass forward
190 9
                $newFormat .= "%$sign$filler$align$size$precision$type";
191 9
                $newArgv[] = array_shift($argv);
192
            }
193 29
            $format = strval($post);
194
        }
195
        // Convert new format back from UTF-8 to the original encoding
196 31
        $newFormat = strval(mb_convert_encoding($newFormat, $encoding, 'UTF-8'));
197 31
        return vsprintf($newFormat, $newArgv);
198
    }
199
}
200