S::replaceByMap()   A
last analyzed

Complexity

Conditions 3
Paths 4

Size

Total Lines 13

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 12

Importance

Changes 0
Metric Value
cc 3
nc 4
nop 3
dl 0
loc 13
ccs 0
cts 8
cp 0
crap 12
rs 9.8333
c 0
b 0
f 0
1
<?php
2
namespace morphos;
3
4
use RuntimeException;
5
6
/**
7
 * Multibyte string helper
8
 */
9
class S
10
{
11
    /** @var string Encoding used for string manipulations */
12
    static protected $encoding;
13
14
    /** @var string[][] */
15
    static protected $cyrillicAlphabet = [
16
        ['Ё', 'Й', 'Ц', 'У', 'К', 'Е', 'Н', 'Г', 'Ш', 'Щ', 'З', 'Х', 'Ъ', 'Ф', 'Ы', 'В', 'А', 'П', 'Р', 'О', 'Л', 'Д', 'Ж', 'Э', 'Я', 'Ч', 'С', 'М', 'И', 'Т', 'Ь', 'Б', 'Ю'],
17
        ['ё', 'й', 'ц', 'у', 'к', 'е', 'н', 'г', 'ш', 'щ', 'з', 'х', 'ъ', 'ф', 'ы', 'в', 'а', 'п', 'р', 'о', 'л', 'д', 'ж', 'э', 'я', 'ч', 'с', 'м', 'и', 'т', 'ь', 'б', 'ю'],
18
    ];
19
20
    /**
21
     * Sets encoding for all operations
22
     * @param string $encoding
23
     * @return void
24
     */
25
    public static function setEncoding($encoding)
26
    {
27
        static::$encoding = $encoding;
28
    }
29
30
    /**
31
     * Returns encoding used for all operations
32
     * @return string
33
     */
34 1767
    public static function getEncoding()
35
    {
36 1767
        return static::$encoding ?: 'utf-8';
37
    }
38
39
    /**
40
     * Calculates count of characters in string.
41
     * @param string $string
42
     * @return int|false
43
     */
44 47
    public static function length($string)
45
    {
46 47
        if (function_exists('mb_strlen')) {
47 47
            return mb_strlen($string, static::getEncoding());
48
        }
49
50
        if (function_exists('iconv_strlen')) {
51
            return iconv_strlen($string, static::getEncoding());
52
        }
53
54
        return false;
55
    }
56
57
    /**
58
     * Slices string like python.
59
     * @param string $string
60
     * @param int $start
61
     * @param int|null $end
62
     * @return string
63
     */
64 1503
    public static function slice($string, $start, $end = null)
65
    {
66 1503
        if ($end !== null) {
67 660
            $end -= $start;
68
        }
69
70 1503
        if (function_exists('mb_substr')) {
71 1503
            return mb_substr($string, $start, $end, static::getEncoding());
72
        }
73
74
        if (function_exists('iconv_substr')) {
75
            return iconv_substr($string, $start, $end ?: iconv_strlen($string), static::getEncoding());
76
        }
77
78
        throw new RuntimeException('Unreachable');
79
    }
80
81
    /**
82
     * Lower case.
83
     * @param string $string
84
     * @return string
85
     */
86 1758 View Code Duplication
    public static function lower($string)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
87
    {
88 1758
        if (function_exists('mb_strtolower')) {
89 1758
            return mb_strtolower($string, static::getEncoding());
90
        }
91
92
        return static::replaceByMap($string, static::$cyrillicAlphabet[0], static::$cyrillicAlphabet[1]);
0 ignored issues
show
Bug introduced by
Since replaceByMap() is declared private, calling it with static will lead to errors in possible sub-classes. You can either use self, or increase the visibility of replaceByMap() to at least protected.

Let’s assume you have a class which uses late-static binding:

class YourClass
{
    private static function getTemperature() {
        return "3422 °C";
}

public static function getSomeVariable()
{
    return static::getTemperature();
}

}

The code above will run fine in your PHP runtime. However, if you now create a sub-class and call the getSomeVariable() on that sub-class, you will receive a runtime error:

class YourSubClass extends YourClass {
      private static function getTemperature() {
        return "-182 °C";
    }
}

print YourSubClass::getSomeVariable(); // Will cause an access error.

In the case above, it makes sense to update SomeClass to use self instead:

class YourClass
{
    private static function getTemperature() {
        return "3422 °C";
    }

    public static function getSomeVariable()
    {
        return self::getTemperature();
    }
}
Loading history...
93
    }
94
95
    /**
96
     * Upper case.
97
     * @param string $string
98
     * @return bool|string
99
     */
100 220 View Code Duplication
    public static function upper($string)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
101
    {
102 220
        if (function_exists('mb_strtoupper')) {
103 220
            return mb_strtoupper($string, static::getEncoding());
104
        }
105
106
        return static::replaceByMap($string, static::$cyrillicAlphabet[1], static::$cyrillicAlphabet[0]);
0 ignored issues
show
Bug introduced by
Since replaceByMap() is declared private, calling it with static will lead to errors in possible sub-classes. You can either use self, or increase the visibility of replaceByMap() to at least protected.

Let’s assume you have a class which uses late-static binding:

class YourClass
{
    private static function getTemperature() {
        return "3422 °C";
}

public static function getSomeVariable()
{
    return static::getTemperature();
}

}

The code above will run fine in your PHP runtime. However, if you now create a sub-class and call the getSomeVariable() on that sub-class, you will receive a runtime error:

class YourSubClass extends YourClass {
      private static function getTemperature() {
        return "-182 °C";
    }
}

print YourSubClass::getSomeVariable(); // Will cause an access error.

In the case above, it makes sense to update SomeClass to use self instead:

class YourClass
{
    private static function getTemperature() {
        return "3422 °C";
    }

    public static function getSomeVariable()
    {
        return self::getTemperature();
    }
}
Loading history...
107
    }
108
109
    /**
110
     * Name case. (ex: Thomas, Lewis). Works properly with separated by '-' words
111
     * @param string $string
112
     * @return bool|string
113
     */
114 218
    public static function name($string)
115
    {
116 218
        if (strpos($string, '-') !== false) {
117
            return implode('-', array_map([__CLASS__, __FUNCTION__], explode('-', $string)));
118
        }
119
120 218
        return static::upper(static::slice($string, 0, 1)).static::lower(static::slice($string, 1));
121
    }
122
123
    /**
124
     * multiple substr_count().
125
     * @param string $string
126
     * @param string[] $chars
127
     * @return int
128
     */
129
    public static function countChars($string, array $chars)
130
    {
131
        if (function_exists('mb_split')) {
132
            return count(mb_split('('.implode('|', $chars).')', $string)) - 1;
133
        }
134
135
        $counter = 0;
136
        foreach ($chars as $char) {
137
            $counter += substr_count($string, $char);
138
        }
139
        return $counter;
140
    }
141
142
    /**
143
     * @param string $string
144
     * @param string $char
145
     * @return int|false
146
     */
147 12
    public static function findFirstPosition($string, $char)
148
    {
149 12
        if (function_exists('mb_strpos')) {
150 12
            return mb_strpos($string, $char, 0, static::getEncoding());
151
        }
152
153
        return strpos($string, $char);
154
    }
155
156
    /**
157
     * @param string $string
158
     * @param string $char
159
     * @return int|false
160
     */
161 6
    public static function findLastPosition($string, $char)
162
    {
163 6
        if (function_exists('mb_strrpos')) {
164 6
            return mb_strrpos($string, $char, 0, static::getEncoding());
165
        }
166
167
        return strrpos($string, $char);
168
    }
169
170
    /**
171
     * @param string $string
172
     * @param string[] $chars
173
     * @return string|false
174
     */
175 79
    public static function findLastPositionForOneOfChars($string, array $chars)
176
    {
177 79
        if (function_exists('mb_strrpos')) {
178 79
            $last_position = false;
179 79
            foreach ($chars as $char) {
180 79
                if (($pos = mb_strrpos($string, $char, 0, static::getEncoding())) !== false) {
181 79
                    if ($pos > $last_position) {
182 79
                        $last_position = $pos;
183
                    }
184
                }
185
            }
186 79
            if ($last_position !== false) {
187 79
                return mb_substr($string, $last_position, null, static::getEncoding());
188
            }
189 13
            return false;
190
        }
191
192
        return false;
193
    }
194
195
    /**
196
     * @param string $string
197
     * @param string $substring
198
     * @param bool $caseSensitive
199
     * @param int $startOffset
200
     * @return int|false
201
     */
202 120
    public static function indexOf($string, $substring, $caseSensitive = false, $startOffset = 0)
203
    {
204 120
        if (function_exists('mb_stripos')) {
205 120
            return $caseSensitive
206
                ? mb_strpos($string, $substring, $startOffset, static::getEncoding())
207 120
                : mb_stripos($string, $substring, $startOffset, static::getEncoding());
208
        }
209
210
        return false;
211
    }
212
213
    /**
214
     * @param string $string
215
     * @param string[] $fromMap
216
     * @param string[] $toMap
217
     * @return string
218
     */
219
    private static function replaceByMap($string, $fromMap, $toMap)
220
    {
221
        $encoding = static::getEncoding();
222
        if ($encoding !== 'utf-8')
223
            $string = iconv($encoding, 'utf-8', $string);
224
225
        $string = strtr($string, array_combine($fromMap, $toMap));
226
227
        if ($encoding !== 'utf-8')
228
            $string = iconv('utf-8', $encoding, $string);
229
230
        return $string;
231
    }
232
233
    /**
234
     * Check that string has one of passed substrings
235
     * @param string $string
236
     * @param string[] $variants
237
     * @return bool
238
     */
239 3
    public static function stringContains($string, array $variants)
240
    {
241 3
        foreach ($variants as $variant) {
242 3
            if (static::findFirstPosition($string, $variant) !== false) {
243 3
                return true;
244
            }
245
        }
246 3
        return false;
247
    }
248
}
249