This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | namespace morphos\Russian; |
||
3 | |||
4 | use morphos\S; |
||
5 | |||
6 | /** |
||
7 | * Rules are from: https://ru.wikipedia.org/wiki/%D0%A1%D0%BA%D0%BB%D0%BE%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5_%D0%B3%D0%B5%D0%BE%D0%B3%D1%80%D0%B0%D1%84%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%B8%D1%85_%D0%BD%D0%B0%D0%B7%D0%B2%D0%B0%D0%BD%D0%B8%D0%B9_%D0%B2_%D1%80%D1%83%D1%81%D1%81%D0%BA%D0%BE%D0%BC_%D1%8F%D0%B7%D1%8B%D0%BA%D0%B5 |
||
8 | */ |
||
9 | class GeographicalNamesInflection extends \morphos\BaseInflection implements Cases |
||
10 | { |
||
11 | use RussianLanguage, CasesHelper; |
||
12 | |||
13 | /** @var bool Настройка склоняемости славянских топонимов на -ов(о), -ев(о), -ин(о), -ын(о) */ |
||
14 | public static $inflectSlavicNames = true; |
||
15 | |||
16 | /** @var string[] */ |
||
17 | protected static $abbreviations = [ |
||
18 | 'сша', |
||
19 | 'оаэ', |
||
20 | 'ссср', |
||
21 | 'юар', |
||
22 | ]; |
||
23 | |||
24 | /** @var string[] */ |
||
25 | protected static $delimiters = [ |
||
26 | ' ', |
||
27 | '-на-', |
||
28 | '-эль-', |
||
29 | '-де-', |
||
30 | '-сюр-', |
||
31 | '-ан-', |
||
32 | '-ла-', |
||
33 | '-', |
||
34 | ]; |
||
35 | |||
36 | /** @var string[] */ |
||
37 | protected static $ovAbnormalExceptions = [ |
||
38 | 'осташков', |
||
39 | ]; |
||
40 | |||
41 | /** |
||
42 | * @var string[] Immutable names or name parts |
||
43 | */ |
||
44 | protected static $immutableNames = [ |
||
45 | 'алматы', |
||
46 | 'сочи', |
||
47 | 'гоа', |
||
48 | 'домодедово', |
||
49 | 'внуково', |
||
50 | 'шереметьево', |
||
51 | 'остафьево', |
||
52 | 'пулково', |
||
53 | |||
54 | // фикс для Марий Эл |
||
55 | 'марий', |
||
56 | 'эл', |
||
57 | |||
58 | // части |
||
59 | 'алма', |
||
60 | 'буда', |
||
61 | 'йошкар', |
||
62 | 'кабардино', |
||
63 | 'карачаево', |
||
64 | 'рублёво', |
||
65 | 'санкт', |
||
66 | 'улан', |
||
67 | 'ханты', |
||
68 | 'орехово', |
||
69 | 'лосино', |
||
70 | 'юрьево', |
||
71 | 'наро', |
||
72 | |||
73 | // Зарубежные названия |
||
74 | 'пунта', |
||
75 | 'куала', |
||
76 | 'рас', |
||
77 | 'шарм', |
||
78 | 'гран', |
||
79 | 'гранд', |
||
80 | 'вильфранш', |
||
81 | 'льорет', |
||
82 | 'андорра', |
||
83 | 'экс', |
||
84 | 'эс', |
||
85 | 'сен', |
||
86 | 'ла', |
||
87 | ]; |
||
88 | |||
89 | /** @var string[] */ |
||
90 | protected static $immutableTriggerPrefixes = [ |
||
91 | 'спас', |
||
92 | 'усть', |
||
93 | 'соль', |
||
94 | ]; |
||
95 | |||
96 | /** @var string[] */ |
||
97 | protected static $runawayVowelsExceptions = [ |
||
98 | 'торжо*к', |
||
99 | 'волоче*к', |
||
100 | 'орё*л', |
||
101 | 'египе*т', |
||
102 | 'лунине*ц', |
||
103 | 'городо*к', |
||
104 | 'новогрудо*к', |
||
105 | 'острове*ц', |
||
106 | 'черепове*ц', |
||
107 | ]; |
||
108 | |||
109 | /** |
||
110 | * @var string[] |
||
111 | * @phpstan-var array<string, string> |
||
112 | */ |
||
113 | protected static $misspellings = [ |
||
114 | 'орел' => 'орёл', |
||
115 | 'рублево' => 'рублёво', |
||
116 | ]; |
||
117 | |||
118 | /** |
||
119 | * @return int[]|false[] |
||
120 | */ |
||
121 | 13 | View Code Duplication | protected static function getRunAwayVowelsList() |
0 ignored issues
–
show
|
|||
122 | { |
||
123 | 13 | $runawayVowelsNormalized = []; |
|
124 | 13 | foreach (static::$runawayVowelsExceptions as $word) { |
|
125 | 13 | $runawayVowelsNormalized[str_replace('*', '', $word)] = S::indexOf($word, '*') - 1; |
|
126 | } |
||
127 | 13 | return $runawayVowelsNormalized; |
|
128 | } |
||
129 | |||
130 | /** |
||
131 | * Проверяет, склоняемо ли название |
||
132 | * @param string $name Название |
||
133 | * @return bool |
||
134 | */ |
||
135 | 2 | public static function isMutable($name) |
|
136 | { |
||
137 | 2 | $name = S::lower($name); |
|
138 | |||
139 | // // ends with 'ы' or 'и': plural form |
||
140 | // if (in_array(S::slice($name, -1), array('и', 'ы'))) |
||
141 | // return false; |
||
142 | |||
143 | 2 | if (in_array($name, static::$abbreviations, true) || in_array($name, static::$immutableNames, true)) { |
|
144 | 2 | return false; |
|
145 | } |
||
146 | |||
147 | if (strpos($name, ' ') !== false) { |
||
148 | // explode() is not applicable because Geographical unit may have few words |
||
149 | $first_part = S::slice($name, 0, S::findFirstPosition($name, ' ')); |
||
0 ignored issues
–
show
|
|||
150 | $last_part = S::slice($name, |
||
151 | S::findLastPosition($name, ' ') + 1); |
||
152 | |||
153 | // город N, село N, хутор N, район N, поселок N, округ N, республика N |
||
154 | // N область, N край, N район, N волость |
||
155 | if (in_array($first_part, ['город', 'село', 'хутор', 'район', 'поселок', 'округ', 'республика'], true) |
||
156 | || in_array($last_part, ['край', 'область', 'район', 'волость'], true)) { |
||
157 | return true; |
||
158 | } |
||
159 | |||
160 | // пгт N |
||
161 | if ($first_part === 'пгт') |
||
162 | return false; |
||
163 | } |
||
164 | |||
165 | if (strpos($name, '-') !== false && S::stringContains($name, static::$immutableTriggerPrefixes)) { |
||
166 | return false; |
||
167 | } |
||
168 | |||
169 | // ends with 'е' or 'о', but not with 'ово/ёво/ево/ино/ыно' |
||
170 | if (in_array(S::slice($name, -1), ['е', 'о'], true) |
||
171 | && !in_array(S::slice($name, -3, -1), ['ов', 'ёв', 'ев', 'ин', 'ын'], true)) { |
||
172 | return (bool)static::$inflectSlavicNames; |
||
173 | } |
||
174 | return true; |
||
175 | } |
||
176 | |||
177 | /** |
||
178 | * Получение всех форм названия |
||
179 | * @param string $name |
||
180 | * @return string[] |
||
181 | * @phpstan-return array<string, string> |
||
182 | * @throws \Exception |
||
183 | */ |
||
184 | 48 | public static function getCases($name) |
|
185 | { |
||
186 | 48 | $name = S::lower($name); |
|
187 | |||
188 | // Проверка на неизменяемость |
||
189 | 48 | if (in_array($name, static::$immutableNames, true) |
|
190 | 48 | || (strpos($name, '-') !== false && S::stringContains($name, static::$immutableTriggerPrefixes)) |
|
191 | ) { |
||
192 | 2 | return array_fill_keys( |
|
193 | 2 | [static::IMENIT, static::RODIT, static::DAT, static::VINIT, static::TVORIT, static::PREDLOJ, static::LOCATIVE] |
|
194 | 2 | , S::name($name)); |
|
195 | } |
||
196 | |||
197 | // Проверка на сложное название |
||
198 | 48 | if (strpos($name, ' ') !== false) { |
|
199 | 9 | $first_part = S::slice($name, 0, S::findFirstPosition($name, ' ')); |
|
0 ignored issues
–
show
|
|||
200 | // город N, село N, хутор N, пгт N |
||
201 | 9 | if (in_array($first_part, ['город', 'село', 'хутор', 'пгт', 'район', 'поселок', 'округ', 'республика'], true)) { |
|
202 | 3 | if ($first_part === 'пгт') |
|
203 | return array_fill_keys( |
||
204 | [static::IMENIT, static::RODIT, static::DAT, static::VINIT, static::TVORIT, static::PREDLOJ, static::LOCATIVE], |
||
205 | 'пгт '.S::name(S::slice($name, 4))); |
||
206 | |||
207 | 3 | if ($first_part === 'республика') { |
|
208 | 1 | $prefix = array_map(['\\morphos\\S', 'name'], NounDeclension::getCases($first_part)); |
|
209 | } else { |
||
210 | 2 | $prefix = NounDeclension::getCases($first_part); |
|
211 | } |
||
212 | 3 | $prefix[Cases::LOCATIVE] = $prefix[Cases::PREDLOJ]; |
|
213 | |||
214 | 3 | return static::composeCasesFromWords([$prefix, |
|
215 | 3 | array_fill_keys( |
|
216 | 3 | array_merge(static::getAllCases(), [\morphos\Russian\Cases::LOCATIVE]), |
|
217 | 3 | S::name(S::slice($name, S::length($first_part) + 1))) |
|
218 | ]); |
||
219 | } |
||
220 | |||
221 | 6 | $last_part = S::slice($name, |
|
222 | 6 | S::findLastPosition($name, ' ') + 1); |
|
223 | // N область, N край |
||
224 | 6 | if (in_array($last_part, ['край', 'область', 'район', 'волость'], true)) { |
|
225 | 2 | $last_part_cases = NounDeclension::getCases($last_part); |
|
226 | 2 | $last_part_cases[Cases::LOCATIVE] = $last_part_cases[Cases::PREDLOJ]; |
|
227 | 2 | return static::composeCasesFromWords( |
|
228 | [ |
||
229 | 2 | static::getCases(S::slice($name, 0, S::findLastPosition($name, ' '))), |
|
0 ignored issues
–
show
|
|||
230 | 2 | $last_part_cases, |
|
231 | ]); |
||
232 | } |
||
233 | } |
||
234 | |||
235 | // Сложное название с разделителем |
||
236 | 45 | foreach (static::$delimiters as $delimiter) { |
|
237 | 45 | if (strpos($name, $delimiter) !== false) { |
|
238 | 7 | $parts = explode($delimiter, $name); |
|
239 | 7 | $result = []; |
|
240 | 7 | foreach ($parts as $i => $part) { |
|
241 | 7 | $result[$i] = static::getCases($part); |
|
242 | } |
||
243 | 45 | return static::composeCasesFromWords($result, $delimiter); |
|
244 | } |
||
245 | } |
||
246 | |||
247 | // Исправление ошибок |
||
248 | 45 | if (array_key_exists($name, static::$misspellings)) { |
|
249 | $name = static::$misspellings[$name]; |
||
250 | } |
||
251 | |||
252 | // Само склонение |
||
253 | 45 | if (!in_array($name, static::$abbreviations, true)) { |
|
254 | 43 | switch (S::slice($name, -2)) { |
|
255 | // Нижний, Русский |
||
256 | 43 | case 'ий': |
|
257 | 3 | $prefix = S::name(S::slice($name, 0, -2)); |
|
258 | return [ |
||
259 | 3 | static::IMENIT => $prefix.'ий', |
|
260 | 3 | static::RODIT => $prefix.(static::isVelarConsonant(S::slice($name, -3, -2)) ? 'ого' : 'его'), |
|
261 | 3 | static::DAT => $prefix.(static::isVelarConsonant(S::slice($name, -3, -2)) ? 'ому' : 'ему'), |
|
262 | 3 | static::VINIT => $prefix.'ий', |
|
263 | 3 | static::TVORIT => $prefix.'им', |
|
264 | 3 | static::PREDLOJ => $prefix.(static::chooseEndingBySonority($prefix, 'ем', 'ом')), |
|
0 ignored issues
–
show
It seems like
$prefix defined by \morphos\S::name(\morphos\S::slice($name, 0, -2)) on line 257 can also be of type boolean ; however, morphos\Russian\RussianL...hooseEndingBySonority() does only seem to accept string , maybe add an additional type check?
If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check: /**
* @return array|string
*/
function returnsDifferentValues($x) {
if ($x) {
return 'foo';
}
return array();
}
$x = returnsDifferentValues($y);
if (is_array($x)) {
// $x is an array.
}
If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.
Loading history...
|
|||
265 | 3 | static::LOCATIVE => $prefix.(static::chooseEndingBySonority($prefix, 'ем', 'ом')), |
|
0 ignored issues
–
show
It seems like
$prefix defined by \morphos\S::name(\morphos\S::slice($name, 0, -2)) on line 257 can also be of type boolean ; however, morphos\Russian\RussianL...hooseEndingBySonority() does only seem to accept string , maybe add an additional type check?
If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check: /**
* @return array|string
*/
function returnsDifferentValues($x) {
if ($x) {
return 'foo';
}
return array();
}
$x = returnsDifferentValues($y);
if (is_array($x)) {
// $x is an array.
}
If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.
Loading history...
|
|||
266 | ]; |
||
267 | |||
268 | // Ростовская |
||
269 | 42 | case 'ая': |
|
270 | 1 | $prefix = S::name(S::slice($name, 0, -2)); |
|
271 | return [ |
||
272 | 1 | static::IMENIT => $prefix.'ая', |
|
273 | 1 | static::RODIT => $prefix.'ой', |
|
274 | 1 | static::DAT => $prefix.'ой', |
|
275 | 1 | static::VINIT => $prefix.'ую', |
|
276 | 1 | static::TVORIT => $prefix.'ой', |
|
277 | 1 | static::PREDLOJ => $prefix.'ой', |
|
278 | 1 | static::LOCATIVE => $prefix.'ой', |
|
279 | ]; |
||
280 | |||
281 | // Нижняя, Верхняя, Средняя |
||
282 | 41 | case 'яя': |
|
283 | $prefix = S::name(S::slice($name, 0, -2)); |
||
284 | return [ |
||
285 | static::IMENIT => $prefix.'яя', |
||
286 | static::RODIT => $prefix.'ей', |
||
287 | static::DAT => $prefix.'ей', |
||
288 | static::VINIT => $prefix.'юю', |
||
289 | static::TVORIT => $prefix.'ей', |
||
290 | static::PREDLOJ => $prefix.'ей', |
||
291 | static::LOCATIVE => $prefix.'ей', |
||
292 | ]; |
||
293 | |||
294 | // Россошь |
||
295 | 41 | case 'шь': |
|
296 | // Пермь, Кемь |
||
297 | 40 | case 'мь': |
|
298 | // Рязань, Назрань |
||
299 | 39 | case 'нь': |
|
300 | // Сысерть |
||
301 | 38 | case 'ть': |
|
302 | // Керчь |
||
303 | 38 | case 'чь': |
|
304 | 4 | $prefix = S::name(S::slice($name, 0, -1)); |
|
305 | return [ |
||
306 | 4 | static::IMENIT => $prefix.'ь', |
|
307 | 4 | static::RODIT => $prefix.'и', |
|
308 | 4 | static::DAT => $prefix.'и', |
|
309 | 4 | static::VINIT => $prefix.'ь', |
|
310 | 4 | static::TVORIT => $prefix.'ью', |
|
311 | 4 | static::PREDLOJ => $prefix.'и', |
|
312 | 4 | static::LOCATIVE => $prefix.'и', |
|
313 | ]; |
||
314 | |||
315 | // Грозный, Благодарный |
||
316 | 37 | case 'ый': |
|
317 | 2 | $prefix = S::name(S::slice($name, 0, -2)); |
|
318 | return [ |
||
319 | 2 | static::IMENIT => $prefix.'ый', |
|
320 | 2 | static::RODIT => $prefix.'ого', |
|
321 | 2 | static::DAT => $prefix.'ому', |
|
322 | 2 | static::VINIT => $prefix.'ый', |
|
323 | 2 | static::TVORIT => $prefix.'ым', |
|
324 | 2 | static::PREDLOJ => $prefix.'ом', |
|
325 | 2 | static::LOCATIVE => $prefix.'ом', |
|
326 | ]; |
||
327 | |||
328 | // Ставрополь, Ярославль, Электросталь |
||
329 | 35 | case 'ль': |
|
330 | 2 | $prefix = S::name(S::slice($name, 0, -1)); |
|
331 | |||
332 | 2 | if ($name === 'электросталь') |
|
333 | return [ |
||
334 | 1 | static::IMENIT => $prefix.'ь', |
|
335 | 1 | static::RODIT => $prefix.'и', |
|
336 | 1 | static::DAT => $prefix.'и', |
|
337 | 1 | static::VINIT => $prefix.'ь', |
|
338 | 1 | static::TVORIT => $prefix.'ью', |
|
339 | 1 | static::PREDLOJ => $prefix.'и', |
|
340 | 1 | static::LOCATIVE => $prefix.'и', |
|
341 | ]; |
||
342 | |||
343 | return [ |
||
344 | 1 | static::IMENIT => $prefix.'ь', |
|
345 | 1 | static::RODIT => $prefix.'я', |
|
346 | 1 | static::DAT => $prefix.'ю', |
|
347 | 1 | static::VINIT => $prefix.'ь', |
|
348 | 1 | static::TVORIT => $prefix.'ем', |
|
349 | 1 | static::PREDLOJ => $prefix.'е', |
|
350 | 1 | static::LOCATIVE => $prefix.'е', |
|
351 | ]; |
||
352 | |||
353 | // Адыгея, Чечня |
||
354 | 33 | case 'ея': |
|
355 | 32 | case 'ня': |
|
356 | 1 | $prefix = S::name(S::slice($name, 0, -1)); |
|
357 | return [ |
||
0 ignored issues
–
show
The expression
return array(static::IME...IVE => $prefix . 'е'); seems to be an array , but some of its elements' types (boolean ) are incompatible with the return type documented by morphos\Russian\Geograph...mesInflection::getCases of type string[] .
If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design. Let’s take a look at an example: class Author {
private $name;
public function __construct($name) {
$this->name = $name;
}
public function getName() {
return $this->name;
}
}
abstract class Post {
public function getAuthor() {
return new Author('Johannes');
}
}
class BlogPost extends Post {
public function getAuthor() {
return 'Johannes';
}
}
class ForumPost extends Post { /* ... */ }
function my_function(Post $post) {
echo strtoupper($post->getAuthor());
}
Our function
Loading history...
|
|||
358 | 1 | static::IMENIT => S::name($name), |
|
359 | 1 | static::RODIT => $prefix.'е', |
|
360 | 1 | static::DAT => $prefix.'е', |
|
361 | 1 | static::VINIT => $prefix.'я', |
|
362 | 1 | static::TVORIT => $prefix.'ей', |
|
363 | 1 | static::PREDLOJ => $prefix.'е', |
|
364 | 1 | static::LOCATIVE => $prefix.'е', |
|
365 | ]; |
||
366 | |||
367 | // Тверь, Анадырь |
||
368 | 32 | case 'рь': |
|
369 | 2 | $prefix = S::name(S::slice($name, 0, -1)); |
|
370 | 2 | $last_vowel = S::slice($prefix, -2, -1); |
|
0 ignored issues
–
show
It seems like
$prefix defined by \morphos\S::name(\morphos\S::slice($name, 0, -1)) on line 369 can also be of type boolean ; however, morphos\S::slice() does only seem to accept string , maybe add an additional type check?
If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check: /**
* @return array|string
*/
function returnsDifferentValues($x) {
if ($x) {
return 'foo';
}
return array();
}
$x = returnsDifferentValues($y);
if (is_array($x)) {
// $x is an array.
}
If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.
Loading history...
|
|||
371 | return [ |
||
372 | 2 | static::IMENIT => $prefix . 'ь', |
|
373 | 2 | static::RODIT => $prefix . (static::isBinaryVowel($last_vowel) ? 'и' : 'я'), |
|
374 | 2 | static::DAT => $prefix . (static::isBinaryVowel($last_vowel) ? 'и' : 'ю'), |
|
375 | 2 | static::VINIT => $prefix . 'ь', |
|
376 | 2 | static::TVORIT => $prefix . (static::isBinaryVowel($last_vowel) ? 'ью' : 'ем'), |
|
377 | 2 | static::PREDLOJ => $prefix . (static::isBinaryVowel($last_vowel) ? 'и' : 'е'), |
|
378 | 2 | static::LOCATIVE => $prefix . (static::isBinaryVowel($last_vowel) ? 'и' : 'е'), |
|
379 | ]; |
||
380 | |||
381 | // Березники, Ессентуки |
||
382 | 30 | case 'ки': |
|
383 | // Старые Дороги |
||
384 | 29 | case 'ги': |
|
385 | // Ушачи, Ивацевичи |
||
386 | 29 | case 'чи': |
|
387 | 3 | $prefix = S::name(S::slice($name, 0, -1)); |
|
388 | return [ |
||
0 ignored issues
–
show
The expression
return array(static::IME...E => $prefix . 'ах'); seems to be an array , but some of its elements' types (boolean ) are incompatible with the return type documented by morphos\Russian\Geograph...mesInflection::getCases of type string[] .
If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design. Let’s take a look at an example: class Author {
private $name;
public function __construct($name) {
$this->name = $name;
}
public function getName() {
return $this->name;
}
}
abstract class Post {
public function getAuthor() {
return new Author('Johannes');
}
}
class BlogPost extends Post {
public function getAuthor() {
return 'Johannes';
}
}
class ForumPost extends Post { /* ... */ }
function my_function(Post $post) {
echo strtoupper($post->getAuthor());
}
Our function
Loading history...
|
|||
389 | 3 | static::IMENIT => $prefix . 'и', |
|
390 | 3 | static::RODIT => ($name === 'луки' |
|
391 | 1 | ? $prefix |
|
392 | 2 | : (S::slice($name, -2) === 'чи' |
|
393 | 1 | ? $prefix . 'ей' |
|
394 | 3 | : $prefix . 'ов')), |
|
395 | 3 | static::DAT => $prefix . 'ам', |
|
396 | 3 | static::VINIT => $prefix . 'и', |
|
397 | 3 | static::TVORIT => $prefix . 'ами', |
|
398 | 3 | static::PREDLOJ => $prefix . 'ах', |
|
399 | 3 | static::LOCATIVE => $prefix . 'ах', |
|
400 | ]; |
||
401 | |||
402 | // Набережные |
||
403 | 28 | case 'ые': |
|
404 | // Великие |
||
405 | 28 | case 'ие': |
|
406 | 2 | $prefix = S::name(S::slice($name, 0, -1)); |
|
407 | return [ |
||
408 | 2 | static::IMENIT => $prefix . 'е', |
|
409 | 2 | static::RODIT => $prefix . 'х', |
|
410 | 2 | static::DAT => $prefix . 'м', |
|
411 | 2 | static::VINIT => $prefix . 'е', |
|
412 | 2 | static::TVORIT => $prefix . 'ми', |
|
413 | 2 | static::PREDLOJ => $prefix . 'х', |
|
414 | 2 | static::LOCATIVE => $prefix . 'х', |
|
415 | ]; |
||
416 | |||
417 | // Челны |
||
418 | 27 | case 'ны': |
|
419 | // Мосты |
||
420 | 26 | case 'ты': |
|
421 | // Столбцы |
||
422 | 26 | case 'цы': |
|
423 | 2 | $prefix = S::name(S::slice($name, 0, -1)); |
|
424 | return [ |
||
425 | 2 | static::IMENIT => $prefix . 'ы', |
|
426 | 2 | static::RODIT => $prefix . 'ов', |
|
427 | 2 | static::DAT => $prefix . 'ам', |
|
428 | 2 | static::VINIT => $prefix . 'ы', |
|
429 | 2 | static::TVORIT => $prefix . 'ами', |
|
430 | 2 | static::PREDLOJ => $prefix . 'ах', |
|
431 | 2 | static::LOCATIVE => $prefix . 'ах', |
|
432 | ]; |
||
433 | |||
434 | // Глубокое |
||
435 | 25 | case 'ое': |
|
436 | 1 | $prefix = S::name(S::slice($name, 0, -2)); |
|
437 | return [ |
||
438 | 1 | static::IMENIT => $prefix.'ое', |
|
439 | 1 | static::RODIT => $prefix.'ого', |
|
440 | 1 | static::DAT => $prefix.'ому', |
|
441 | 1 | static::VINIT => $prefix.'ое', |
|
442 | 1 | static::TVORIT => $prefix.'им', |
|
443 | 1 | static::PREDLOJ => $prefix.'ом', |
|
444 | 1 | static::LOCATIVE => $prefix.'ом', |
|
445 | ]; |
||
446 | } |
||
447 | |||
448 | 24 | switch (S::slice($name, -1)) { |
|
449 | 24 | case 'р': |
|
450 | // Бор |
||
451 | $prefix = S::name(S::slice($name, 0, -1)); |
||
452 | return [ |
||
453 | static::IMENIT => $prefix.'р', |
||
454 | static::RODIT => $prefix.'ра', |
||
455 | static::DAT => $prefix.'ру', |
||
456 | static::VINIT => $prefix.'р', |
||
457 | static::TVORIT => $prefix.'ром', |
||
458 | static::PREDLOJ => $prefix.'ре', |
||
459 | static::LOCATIVE => $prefix.'ру', |
||
460 | ]; |
||
461 | |||
462 | 24 | case 'ы': |
|
463 | // Чебоксары, Шахты |
||
464 | 1 | $prefix = S::name(S::slice($name, 0, -1)); |
|
465 | return [ |
||
0 ignored issues
–
show
The expression
return array(static::IME...E => $prefix . 'ах'); seems to be an array , but some of its elements' types (boolean ) are incompatible with the return type documented by morphos\Russian\Geograph...mesInflection::getCases of type string[] .
If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design. Let’s take a look at an example: class Author {
private $name;
public function __construct($name) {
$this->name = $name;
}
public function getName() {
return $this->name;
}
}
abstract class Post {
public function getAuthor() {
return new Author('Johannes');
}
}
class BlogPost extends Post {
public function getAuthor() {
return 'Johannes';
}
}
class ForumPost extends Post { /* ... */ }
function my_function(Post $post) {
echo strtoupper($post->getAuthor());
}
Our function
Loading history...
|
|||
466 | 1 | static::IMENIT => $prefix.'ы', |
|
467 | 1 | static::RODIT => $prefix, |
|
468 | 1 | static::DAT => $prefix.'ам', |
|
469 | 1 | static::VINIT => $prefix.'ы', |
|
470 | 1 | static::TVORIT => $prefix.'ами', |
|
471 | 1 | static::PREDLOJ => $prefix.'ах', |
|
472 | 1 | static::LOCATIVE => $prefix.'ах', |
|
473 | ]; |
||
474 | |||
475 | 23 | case 'я': |
|
476 | // Азия |
||
477 | 1 | $prefix = S::name(S::slice($name, 0, -1)); |
|
478 | return [ |
||
0 ignored issues
–
show
The expression
return array(static::IME...IVE => $prefix . 'и'); seems to be an array , but some of its elements' types (boolean ) are incompatible with the return type documented by morphos\Russian\Geograph...mesInflection::getCases of type string[] .
If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design. Let’s take a look at an example: class Author {
private $name;
public function __construct($name) {
$this->name = $name;
}
public function getName() {
return $this->name;
}
}
abstract class Post {
public function getAuthor() {
return new Author('Johannes');
}
}
class BlogPost extends Post {
public function getAuthor() {
return 'Johannes';
}
}
class ForumPost extends Post { /* ... */ }
function my_function(Post $post) {
echo strtoupper($post->getAuthor());
}
Our function
Loading history...
|
|||
479 | 1 | static::IMENIT => S::name($name), |
|
480 | 1 | static::RODIT => $prefix.'и', |
|
481 | 1 | static::DAT => $prefix.'и', |
|
482 | 1 | static::VINIT => $prefix.'ю', |
|
483 | 1 | static::TVORIT => $prefix.'ей', |
|
484 | 1 | static::PREDLOJ => $prefix.'и', |
|
485 | 1 | static::LOCATIVE => $prefix.'и', |
|
486 | ]; |
||
487 | |||
488 | 22 | case 'а': |
|
489 | // Москва, Рига |
||
490 | 5 | $prefix = S::name(S::slice($name, 0, -1)); |
|
491 | return [ |
||
492 | 5 | static::IMENIT => $prefix.'а', |
|
493 | 5 | static::RODIT => $prefix.(static::isVelarConsonant(S::slice($name, -2, -1)) || static::isHissingConsonant(S::slice($name, -2, -1)) ? 'и' : 'ы'), |
|
494 | 5 | static::DAT => $prefix.'е', |
|
495 | 5 | static::VINIT => $prefix.'у', |
|
496 | 5 | static::TVORIT => $prefix.'ой', |
|
497 | 5 | static::PREDLOJ => $prefix.'е', |
|
498 | 5 | static::LOCATIVE => $prefix.'е', |
|
499 | ]; |
||
500 | |||
501 | 17 | case 'й': |
|
502 | // Ишимбай |
||
503 | 2 | $prefix = S::name(S::slice($name, 0, -1)); |
|
504 | return [ |
||
505 | 2 | static::IMENIT => $prefix . 'й', |
|
506 | 2 | static::RODIT => $prefix . 'я', |
|
507 | 2 | static::DAT => $prefix . 'ю', |
|
508 | 2 | static::VINIT => $prefix . 'й', |
|
509 | 2 | static::TVORIT => $prefix . 'ем', |
|
510 | 2 | static::PREDLOJ => $prefix . 'е', |
|
511 | 2 | static::LOCATIVE => $prefix . 'е', |
|
512 | ]; |
||
513 | } |
||
514 | |||
515 | 15 | if (static::isConsonant($last_char = S::slice($name, -1)) && !in_array($name, static::$ovAbnormalExceptions, true)) { |
|
516 | 13 | $runaway_vowels_list = static::getRunAwayVowelsList(); |
|
517 | |||
518 | // if run-away vowel in name |
||
519 | 13 | if (isset($runaway_vowels_list[$name])) { |
|
520 | 4 | $runaway_vowel_offset = $runaway_vowels_list[$name]; |
|
521 | 4 | $prefix = S::name(S::slice($name, 0, $runaway_vowel_offset) . S::slice($name, $runaway_vowel_offset + 1)); |
|
0 ignored issues
–
show
It seems like
$runaway_vowel_offset defined by $runaway_vowels_list[$name] on line 520 can also be of type false ; however, morphos\S::slice() does only seem to accept integer|null , did you maybe forget to handle an error condition?
This check looks for type mismatches where the missing type is Consider the follow example <?php
function getDate($date)
{
if ($date !== null) {
return new DateTime($date);
}
return false;
}
This function either returns a new
Loading history...
|
|||
522 | } else { |
||
523 | 9 | $prefix = S::name($name); |
|
524 | } |
||
525 | |||
526 | // Париж, Валаам, Киев |
||
527 | return [ |
||
0 ignored issues
–
show
The expression
return array(static::IME... seems to be an array , but some of its elements' types (boolean ) are incompatible with the return type documented by morphos\Russian\Geograph...mesInflection::getCases of type string[] .
If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design. Let’s take a look at an example: class Author {
private $name;
public function __construct($name) {
$this->name = $name;
}
public function getName() {
return $this->name;
}
}
abstract class Post {
public function getAuthor() {
return new Author('Johannes');
}
}
class BlogPost extends Post {
public function getAuthor() {
return 'Johannes';
}
}
class ForumPost extends Post { /* ... */ }
function my_function(Post $post) {
echo strtoupper($post->getAuthor());
}
Our function
Loading history...
|
|||
528 | 13 | static::IMENIT => S::name($name), |
|
529 | 13 | static::RODIT => $prefix . 'а', |
|
530 | 13 | static::DAT => $prefix . 'у', |
|
531 | 13 | static::VINIT => S::name($name), |
|
532 | 13 | static::TVORIT => $prefix . ( |
|
533 | 13 | static::isVelarConsonant(S::slice($name, -2, -1)) |
|
534 | 13 | || static::isHissingConsonant($last_char) |
|
535 | 13 | ? 'ем' : 'ом'), |
|
536 | 13 | static::PREDLOJ => $prefix . 'е', |
|
537 | 13 | static::LOCATIVE => $prefix.($name === 'крым' ? 'у' : 'е'), |
|
538 | ]; |
||
539 | } |
||
540 | |||
541 | // ов, ово, ёв, ёво, ев, ево, ... |
||
542 | 3 | $suffixes = ['ов', 'ёв', 'ев', 'ин', 'ын']; |
|
543 | 3 | if (static::$inflectSlavicNames && ( |
|
544 | 3 | (in_array(S::slice($name, -1), ['е', 'о'], true) && in_array(S::slice($name, -3, -1), $suffixes, true)) |
|
545 | 3 | || in_array(S::slice($name, -2), $suffixes, true) |
|
546 | )) { |
||
547 | // ово, ёво, ... |
||
548 | 2 | if (in_array(S::slice($name, -3, -1), $suffixes, true)) { |
|
549 | 1 | $prefix = S::name(S::slice($name, 0, -1)); |
|
550 | } |
||
551 | // ов, её, ... |
||
552 | 1 | elseif (in_array(S::slice($name, -2), $suffixes, true)) { |
|
553 | 1 | $prefix = S::name($name); |
|
554 | } else { |
||
555 | $prefix = ''; |
||
556 | } |
||
557 | |||
558 | return [ |
||
0 ignored issues
–
show
The expression
return array(static::IME...IVE => $prefix . 'е'); seems to be an array , but some of its elements' types (boolean ) are incompatible with the return type documented by morphos\Russian\Geograph...mesInflection::getCases of type string[] .
If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design. Let’s take a look at an example: class Author {
private $name;
public function __construct($name) {
$this->name = $name;
}
public function getName() {
return $this->name;
}
}
abstract class Post {
public function getAuthor() {
return new Author('Johannes');
}
}
class BlogPost extends Post {
public function getAuthor() {
return 'Johannes';
}
}
class ForumPost extends Post { /* ... */ }
function my_function(Post $post) {
echo strtoupper($post->getAuthor());
}
Our function
Loading history...
|
|||
559 | 2 | static::IMENIT => S::name($name), |
|
560 | 2 | static::RODIT => $prefix.'а', |
|
561 | 2 | static::DAT => $prefix.'у', |
|
562 | 2 | static::VINIT => S::name($name), |
|
563 | 2 | static::TVORIT => $name !== 'осташков' ? $prefix.'ом' : $prefix.'ым', |
|
564 | 2 | static::PREDLOJ => $prefix.'е', |
|
565 | 2 | static::LOCATIVE => $prefix.'е', |
|
566 | ]; |
||
567 | } |
||
568 | } |
||
569 | |||
570 | // if no rules matches or name is immutable |
||
571 | 3 | $name = in_array($name, static::$abbreviations, true) ? S::upper($name) : S::name($name); |
|
572 | 3 | return array_fill_keys( |
|
573 | 3 | [static::IMENIT, static::RODIT, static::DAT, static::VINIT, static::TVORIT, static::PREDLOJ, static::LOCATIVE], |
|
574 | 3 | $name); |
|
575 | } |
||
576 | |||
577 | /** |
||
578 | * Получение одной формы (падежа) названия. |
||
579 | * @param string $name Название |
||
580 | * @param string $case Падеж. Одна из констант {@see \morphos\Russian\Cases} или {@see \morphos\Cases}. |
||
581 | * @see \morphos\Russian\Cases |
||
582 | * @return string |
||
583 | * @throws \Exception |
||
584 | */ |
||
585 | public static function getCase($name, $case) |
||
586 | { |
||
587 | $case = static::canonizeCase($case); |
||
588 | $forms = static::getCases($name); |
||
589 | return $forms[$case]; |
||
590 | } |
||
591 | } |
||
592 |
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.