Test Failed
Pull Request — master (#11)
by
unknown
04:03
created

Sprintf::mb_vsprintf()   F

Complexity

Conditions 17
Paths 344

Size

Total Lines 80
Code Lines 45

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 306

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 45
c 1
b 0
f 0
dl 0
loc 80
ccs 0
cts 43
cp 0
rs 2.5833
cc 17
nc 344
nop 3
crap 306

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
 * This file is part of the Zemit Framework.
4
 *
5
 * (c) Zemit Team <[email protected]>
6
 *
7
 * For the full copyright and license information, please view the LICENSE.txt
8
 * file that was distributed with this source code.
9
 */
10
11
namespace Zemit\Utils;
12
13
/**
14
 * Class Sprintf
15
 * @todo test & use
16
 *
17
 * @author Julien Turbide <[email protected]>
18
 * @copyright Zemit Team <[email protected]>
19
 *
20
 * @since 1.0
21
 * @version 1.0
22
 *
23
 * @package Zemit\Utils
24
 */
25
class Sprintf
26
{
27
    public static function implodeArrayMapSprintf($array = array(), $implode = ' ', $sprintf = '%s')
28
    {
29
        return implode($implode, array_map(function ($value, $key) use ($sprintf) {
30
            return self::mb_sprintf($sprintf, $value, $key);
31
        }, $array, array_keys($array)));
32
    }
33
    
34
    /**
35
     * version of sprintf for cases where named arguments are desired (php syntax)
36
     *
37
     * with sprintf: sprintf('second: %2$s ; first: %1$s', '1st', '2nd');
38
     *
39
     * with sprintfn: sprintfn('second: %second$s ; first: %first$s', array(
40
     *  'first' => '1st',
41
     *  'second'=> '2nd'
42
     * ));
43
     *
44
     * @param string $format sprintf format string, with any number of named arguments
45
     * @param array $args array of [ 'arg_name' => 'arg value', ... ] replacements to be made
46
     * @return string|false result of sprintf call, or bool false on error
47
     */
48
    public static function sprintfn($format, $args = array())
49
    {
50
        if (!is_array($args)) {
0 ignored issues
show
introduced by
The condition is_array($args) is always true.
Loading history...
51
            if (is_object($args)) {
52
                $args = (array)$args;
53
            }
54
        }
55
        // map of argument names to their corresponding sprintf numeric argument value
56
//        $arg_nums = array_slice(array_flip(array_keys(array(0 => 0) + $args)), 1);
57
        $arg_nums = array_keys($args);
58
        array_unshift($arg_nums, 0);
59
        $arg_nums = array_flip(array_slice($arg_nums, 1, null, true));
60
        
61
        // find the next named argument. each search starts at the end of the previous replacement.
62
        for ($pos = 0; preg_match('/(?<=%)([a-zA-Z_]\w*)(?=\$)/', $format, $match, PREG_OFFSET_CAPTURE, $pos);) {
63
            $arg_pos = $match[0][1];
64
            $arg_len = strlen($match[0][0]);
65
            $arg_key = $match[1][0];
66
            
67
            // programmer did not supply a value for the named argument found in the format string
68
            if (! array_key_exists($arg_key, $arg_nums)) {
69
                user_error("sprintfn(): Missing argument '${arg_key}'", E_USER_WARNING);
70
                return false;
71
            }
72
            
73
            // replace the named argument with the corresponding numeric one
74
            $format = substr_replace($format, $replace = $arg_nums[$arg_key], $arg_pos, $arg_len);
75
            $pos = $arg_pos + strlen($replace); // skip to end of replacement for next iteration
76
        }
77
        
78
        return vsprintf($format, array_values($args));
0 ignored issues
show
Bug introduced by
It seems like $format can also be of type array; however, parameter $format of vsprintf() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

78
        return vsprintf(/** @scrutinizer ignore-type */ $format, array_values($args));
Loading history...
79
    }
80
    
81
    /**
82
     * Return a formatted multibyte string
83
     * A more complete and working version of mb_sprintf and mb_vsprintf.
84
     * It should work with any "ASCII preserving" encoding such as UTF-8 and all the ISO-8859 charsets.
85
     * It handles sign, padding, alignment, width and precision. Argument swapping is not handled.
86
     * @link http://php.net/manual/en/function.sprintf.php#89020
87
     *
88
     * @param string $format <p>
89
     * The format string is composed of zero or more directives:
90
     * ordinary characters (excluding %) that are
91
     * copied directly to the result, and conversion
92
     * specifications, each of which results in fetching its
93
     * own parameter. This applies to both sprintf
94
     * and printf.
95
     * </p>
96
     * <p>
97
     * Each conversion specification consists of a percent sign
98
     * (%), followed by one or more of these
99
     * elements, in order:
100
     * An optional sign specifier that forces a sign
101
     * (- or +) to be used on a number. By default, only the - sign is used
102
     * on a number if it's negative. This specifier forces positive numbers
103
     * to have the + sign attached as well, and was added in PHP 4.3.0.
104
     * @param mixed $args [optional] <p>
105
     * </p>
106
     * @param mixed $_ [optional]
107
     *
108
     * @return string a string produced according to the formatting string
109
     * format.
110
     */
111
    public static function mb_sprintf($format, $args = null, $_ = null)
0 ignored issues
show
Coding Style introduced by
Method name "Sprintf::mb_sprintf" is not in camel caps format
Loading history...
112
    {
113
        $argv = func_get_args();
114
        array_shift($argv);
115
        return self::mb_vsprintf($format, $argv);
116
    }
117
    
118
    /**
119
     * Return a formatted string
120
     * A more complete and working version of mb_sprintf and mb_vsprintf.
121
     * It should work with any "ASCII preserving" encoding such as UTF-8 and all the ISO-8859 charsets.
122
     * It handles sign, padding, alignment, width and precision. Argument swapping is not handled.
123
     * Works with all encodings in format and arguments.
124
     * Supported: Sign, padding, alignment, width and precision.
125
     * Not supported: Argument swapping.
126
     * @link http://php.net/manual/en/function.sprintf.php#89020
127
     *
128
     * @param string $format <p>
129
     * See sprintf for a description of
130
     * format.
131
     * </p>
132
     * @param array $args <p>
133
     * </p>
134
     *
135
     * @return string Return array values as a formatted string according to
136
     * format (which is described in the documentation
137
     * for sprintf).
138
     */
139
    public static function mb_vsprintf($format, $argv, $encoding = null)
0 ignored issues
show
Coding Style introduced by
Method name "Sprintf::mb_vsprintf" is not in camel caps format
Loading history...
140
    {
141
        if (!is_array($argv)) {
142
            $argv = array($argv);
143
        }
144
        
145
        if (is_null($encoding)) {
146
            $encoding = mb_internal_encoding();
147
        }
148
        
149
        // Use UTF-8 in the format so we can use the u flag in preg_split
150
        $format = mb_convert_encoding($format, 'UTF-8', $encoding);
151
        
152
        $newformat = ""; // build a new format in UTF-8
153
        $newargv = array(); // unhandled args in unchanged encoding
154
        
155
        while ($format !== "") {
156
            // Split the format in two parts: $pre and $post by the first %-directive
157
            // We get also the matched groups
158
            @list ($pre, $sign, $filler, $align, $size, $precision, $type, $post) =
159
                preg_split(
160
                    "!\%(\+?)('.|[0 ]|)(-?)([1-9][0-9]*|)(\.[1-9][0-9]*|)([%a-zA-Z])!u",
161
                    $format,
0 ignored issues
show
Bug introduced by
It seems like $format can also be of type array; however, parameter $subject of preg_split() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

161
                    /** @scrutinizer ignore-type */ $format,
Loading history...
162
                    2,
163
                    PREG_SPLIT_DELIM_CAPTURE
164
                );
165
166
            $newformat .= mb_convert_encoding($pre, $encoding, 'UTF-8');
167
            
168
            if ($type == '') {
169
                // didn't match. do nothing. this is the last iteration.
170
            } elseif ($type == '%') {
171
                // an escaped %
172
                $newformat .= '%%';
173
            } elseif ($type == 's') {
174
                $arg = array_shift($argv);
175
                $arg = mb_convert_encoding($arg, 'UTF-8', $encoding);
176
                $padding_pre = '';
177
                $padding_post = '';
178
                
179
                // truncate $arg
180
                if ($precision !== '') {
181
                    $precision = intval(substr($precision, 1));
182
                    if ($precision > 0 && mb_strlen($arg, $encoding) > $precision) {
0 ignored issues
show
Bug introduced by
It seems like $arg can also be of type array; however, parameter $string of mb_strlen() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

182
                    if ($precision > 0 && mb_strlen(/** @scrutinizer ignore-type */ $arg, $encoding) > $precision) {
Loading history...
183
                        $arg = mb_substr($precision, 0, $precision, $encoding);
184
                    }
185
                }
186
                
187
                // define padding
188
                if ($size > 0) {
189
                    $arglen = mb_strlen($arg, $encoding);
190
                    if ($arglen < $size) {
191
                        if ($filler === '') {
192
                            $filler = ' ';
193
                        }
194
                        if ($align == '-') {
195
                            $padding_post = str_repeat($filler, $size - $arglen);
196
                        } else {
197
                            $padding_pre = str_repeat($filler, $size - $arglen);
198
                        }
199
                    }
200
                }
201
                
202
                // escape % and pass it forward
203
                $newformat .= $padding_pre . str_replace('%', '%%', $arg) . $padding_post;
204
            } else {
205
                // another type, pass forward
206
                $newformat .= "%$sign$filler$align$size$precision$type";
207
                $newargv[] = array_shift($argv);
208
            }
209
210
            if (strlen($post) === 1 && $post == ']') {
211
                $newformat .= mb_convert_encoding($post, $encoding, 'UTF-8');
212
                $post = '';
213
            }
214
            $format = strval($post);
215
        }
216
        // Convert new format back from UTF-8 to the original encoding
217
        $newformat = mb_convert_encoding($newformat, $encoding, 'UTF-8');
218
        return !empty($newargv)? vsprintf($newformat, $newargv) : $newformat;
0 ignored issues
show
Bug introduced by
It seems like $newformat can also be of type array; however, parameter $format of vsprintf() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

218
        return !empty($newargv)? vsprintf(/** @scrutinizer ignore-type */ $newformat, $newargv) : $newformat;
Loading history...
Bug Best Practice introduced by
The expression return ! empty($newargv)... $newargv) : $newformat also could return the type array which is incompatible with the documented return type string.
Loading history...
219
    }
220
}
221