1
|
|
|
<?php |
2
|
|
|
namespace morphos\Russian; |
3
|
|
|
|
4
|
|
|
use morphos\S; |
5
|
|
|
|
6
|
|
|
/** |
7
|
|
|
* Rules are from: http://www.imena.org/decl_mn.html / http://www.imena.org/decl_fn.html |
8
|
|
|
* and http://rus.omgpu.ru/2016/04/18/%D1%81%D0%BA%D0%BB%D0%BE%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5-%D0%BB%D0%B8%D1%87%D0%BD%D1%8B%D1%85-%D0%B8%D0%BC%D1%91%D0%BD/ |
9
|
|
|
*/ |
10
|
|
|
class FirstNamesInflection extends \morphos\NamesInflection implements Cases |
11
|
|
|
{ |
12
|
|
|
use RussianLanguage, CasesHelper; |
13
|
|
|
|
14
|
|
|
protected static $exceptions = [ |
15
|
|
|
'лев' => [ |
16
|
|
|
self::IMENIT => 'Лев', |
17
|
|
|
self::RODIT => 'Льва', |
18
|
|
|
self::DAT => 'Льву', |
19
|
|
|
self::VINIT => 'Льва', |
20
|
|
|
self::TVORIT => 'Львом', |
21
|
|
|
self::PREDLOJ => 'Льве', |
22
|
|
|
], |
23
|
|
|
'павел' => [ |
24
|
|
|
self::IMENIT => 'Павел', |
25
|
|
|
self::RODIT => 'Павла', |
26
|
|
|
self::DAT => 'Павлу', |
27
|
|
|
self::VINIT => 'Павла', |
28
|
|
|
self::TVORIT => 'Павлом', |
29
|
|
|
self::PREDLOJ => 'Павле', |
30
|
|
|
] |
31
|
|
|
]; |
32
|
|
|
|
33
|
|
|
protected static $menNames = [ |
34
|
|
|
'абрам', 'аверьян', 'авраам', 'агафон', 'адам', 'азар', 'акакий', 'аким', 'аксён', 'александр', 'алексей', |
35
|
|
|
'альберт', 'анатолий', 'андрей', 'андрон', 'антип', 'антон', 'аполлон', 'аристарх', 'аркадий', 'арнольд', |
36
|
|
|
'арсений', 'арсентий', 'артем', 'артём', 'артемий', 'артур', 'аскольд', 'афанасий', 'богдан', 'борис', |
37
|
|
|
'борислав', 'бронислав', 'вадим', 'валентин', 'валерий', 'варлам', 'василий', 'венедикт', 'вениамин', |
38
|
|
|
'веньямин', 'венцеслав', 'виктор', 'виген', 'вилен', 'виталий', 'владилен', 'владимир', 'владислав', 'владлен', |
39
|
|
|
'вова', 'всеволод', 'всеслав', 'вячеслав', 'гавриил', 'геннадий', 'георгий', 'герман', 'глеб', 'григорий', |
40
|
|
|
'давид', 'даниил', 'данил', 'данила', 'демьян', 'денис', 'димитрий', 'дмитрий', 'добрыня', 'евгений', 'евдоким', |
41
|
|
|
'евсей', 'егор', 'емельян', 'еремей', 'ермолай', 'ерофей', 'ефим', 'захар', 'иван', 'игнат', 'игорь', |
42
|
|
|
'илларион', 'иларион', 'илья', 'иосиф', 'казимир', 'касьян', 'кирилл', 'кондрат', 'константин', 'кузьма', |
43
|
|
|
'лавр', 'лаврентий', 'лазарь', 'ларион', 'лев', 'леонард', 'леонид', 'лука', 'максим', 'марат', 'мартын', |
44
|
|
|
'матвей', 'мефодий', 'мирон', 'михаил', 'моисей', 'назар', 'никита', 'николай', 'олег', 'осип', 'остап', |
45
|
|
|
'павел', 'панкрат', 'пантелей', 'парамон', 'пётр', 'петр', 'платон', 'потап', 'прохор', 'роберт', 'ростислав', |
46
|
|
|
'савва', 'савелий', 'семён', 'семен', 'сергей', 'сидор', 'спартак', 'тарас', 'терентий', 'тимофей', 'тимур', |
47
|
|
|
'тихон', 'ульян', 'фёдор', 'федор', 'федот', 'феликс', 'фирс', 'фома', 'харитон', 'харлам', 'эдуард', |
48
|
|
|
'эммануил', 'эраст', 'юлиан', 'юлий', 'юрий', 'яков', 'ян', 'ярослав', |
49
|
|
|
]; |
50
|
|
|
|
51
|
|
|
protected static $womenNames = [ |
52
|
|
|
'авдотья', 'аврора', 'агата', 'агния', 'агриппина', 'ада', 'аксинья', 'алевтина', 'александра', 'алёна', |
53
|
|
|
'алена', 'алина', 'алиса', 'алла', 'альбина', 'амалия', 'анастасия', 'ангелина', 'анжела', 'анжелика', 'анна', |
54
|
|
|
'антонина', 'анфиса', 'арина', 'белла', 'божена', 'валентина', 'валерия', 'ванда', 'варвара', 'василина', |
55
|
|
|
'василиса', 'вера', 'вероника', 'виктория', 'виола', 'виолетта', 'вита', 'виталия', 'владислава', 'власта', |
56
|
|
|
'галина', 'глафира', 'дарья', 'диана', 'дина', 'ева', 'евгения', 'евдокия', 'евлампия', 'екатерина', 'елена', |
57
|
|
|
'елизавета', 'ефросиния', 'ефросинья', 'жанна', 'зиновия', 'злата', 'зоя', 'ивонна', 'изольда', 'илона', 'инга', |
58
|
|
|
'инесса', 'инна', 'ирина', 'ия', 'капитолина', 'карина', 'каролина', 'кира', 'клавдия', 'клара', 'клеопатра', |
59
|
|
|
'кристина', 'ксения', 'лада', 'лариса', 'лиана', 'лидия', 'лилия', 'лина', 'лия', 'лора', 'любава', 'любовь', |
60
|
|
|
'людмила', 'майя', 'маргарита', 'марианна', 'мариетта', 'марина', 'мария', 'марья', 'марта', 'марфа', 'марьяна', |
61
|
|
|
'матрёна', 'матрена', 'матрона', 'милена', 'милослава', 'мирослава', 'муза', 'надежда', 'настасия', 'настасья', |
62
|
|
|
'наталия', 'наталья', 'нелли', 'ника', 'нина', 'нинель', 'нонна', 'оксана', 'олимпиада', 'ольга', 'пелагея', |
63
|
|
|
'полина', 'прасковья', 'раиса', 'рената', 'римма', 'роза', 'роксана', 'руфь', 'сарра', 'светлана', 'серафима', |
64
|
|
|
'снежана', 'софья', 'софия', 'стелла', 'степанида', 'стефания', 'таисия', 'таисья', 'тамара', 'татьяна', |
65
|
|
|
'ульяна', 'устиния', 'устинья', 'фаина', 'фёкла', 'фекла', 'феодора', 'хаврония', 'христина', 'эвелина', |
66
|
|
|
'эдита', 'элеонора', 'элла', 'эльвира', 'эмилия', 'эмма', 'юдифь', 'юлиана', 'юлия', 'ядвига', 'яна', |
67
|
|
|
'ярослава', |
68
|
|
|
]; |
69
|
|
|
|
70
|
|
|
protected static $immutableNames = [ |
71
|
|
|
'николя', |
72
|
|
|
]; |
73
|
|
|
|
74
|
|
|
/** |
75
|
|
|
* Checks if name is mutable |
76
|
|
|
* @param string $name |
77
|
|
|
* @param null|string $gender |
78
|
|
|
* @return bool |
79
|
|
|
*/ |
80
|
716 |
|
public static function isMutable($name, $gender = null) |
81
|
|
|
{ |
82
|
716 |
|
$name = S::lower($name); |
83
|
|
|
|
84
|
716 |
|
if (in_array($name, self::$immutableNames, true)) { |
85
|
|
|
return false; |
86
|
|
|
} |
87
|
|
|
|
88
|
716 |
|
if ($gender === null) { |
89
|
|
|
$gender = self::detectGender($name); |
90
|
|
|
} |
91
|
|
|
|
92
|
|
|
// man rules |
93
|
716 |
|
if ($gender === self::MALE) { |
94
|
|
|
// soft consonant |
95
|
451 |
|
if (S::lower(S::slice($name, -1)) == 'ь' && self::isConsonant(S::slice($name, -2, -1))) { |
|
|
|
|
96
|
14 |
|
return true; |
97
|
437 |
|
} elseif (in_array(S::slice($name, -1), array_diff(self::$consonants, ['й', /*'Ч', 'Щ'*/]), true)) { // hard consonant |
|
|
|
|
98
|
259 |
|
return true; |
99
|
178 |
|
} elseif (S::slice($name, -1) == 'й') { |
|
|
|
|
100
|
104 |
|
return true; |
101
|
74 |
View Code Duplication |
} else if (in_array(S::slice($name, -2), ['ло', 'ко'], true)) { |
|
|
|
|
102
|
74 |
|
return true; |
103
|
|
|
} |
104
|
265 |
|
} else if ($gender === self::FEMALE) { |
105
|
|
|
// soft consonant |
106
|
265 |
|
if (S::lower(S::slice($name, -1)) == 'ь' && self::isConsonant(S::slice($name, -2, -1))) { |
|
|
|
|
107
|
4 |
|
return true; |
108
|
261 |
|
} else if (self::isHissingConsonant(S::slice($name, -1))) { |
|
|
|
|
109
|
5 |
|
return true; |
110
|
|
|
} |
111
|
|
|
} |
112
|
|
|
|
113
|
|
|
// common rules |
114
|
326 |
|
if ((in_array(S::slice($name, -1), ['а', 'я']) && !self::isVowel(S::slice($name, -2, -1))) || in_array(S::slice($name, -2), ['ия', 'ья', 'ея', 'оя'], true)) { |
|
|
|
|
115
|
275 |
|
return true; |
116
|
|
|
} |
117
|
|
|
|
118
|
51 |
|
return false; |
119
|
|
|
} |
120
|
|
|
|
121
|
|
|
/** |
122
|
|
|
* @param $name |
123
|
|
|
* @return string |
124
|
|
|
*/ |
125
|
510 |
|
public static function detectGender($name) |
126
|
|
|
{ |
127
|
510 |
|
$name = S::lower($name); |
128
|
510 |
|
if (in_array($name, self::$menNames, true)) { |
129
|
121 |
|
return self::MALE; |
130
|
390 |
|
} elseif (in_array($name, self::$womenNames, true)) { |
131
|
111 |
|
return self::FEMALE; |
132
|
|
|
} |
133
|
|
|
|
134
|
279 |
|
$man = $woman = 0; |
135
|
279 |
|
$last1 = S::slice($name, -1); |
|
|
|
|
136
|
279 |
|
$last2 = S::slice($name, -2); |
|
|
|
|
137
|
279 |
|
$last3 = S::slice($name, -3); |
|
|
|
|
138
|
|
|
|
139
|
|
|
// try to detect gender by some statistical rules |
140
|
|
|
// |
141
|
279 |
|
if ($last1 == 'й') { |
142
|
48 |
|
$man += 0.9; |
143
|
|
|
} |
144
|
279 |
|
if ($last1 == 'ь') { |
145
|
|
|
$man += 0.02; |
146
|
|
|
} |
147
|
279 |
|
if (in_array($last1, self::$consonants, true)) { |
148
|
199 |
|
$man += 0.01; |
149
|
|
|
} |
150
|
279 |
|
if (in_array($last2, ['он', 'ов', 'ав', 'ам', 'ол', 'ан', 'рд', 'мп'], true)) { |
151
|
47 |
|
$man += 0.3; |
152
|
|
|
} |
153
|
279 |
|
if (in_array($last2, ['вь', 'фь', 'ль'], true)) { |
154
|
|
|
$woman += 0.1; |
155
|
|
|
} |
156
|
279 |
|
if (in_array($last2, ['ла'], true)) { |
157
|
4 |
|
$woman += 0.04; |
158
|
|
|
} |
159
|
279 |
|
if (in_array($last2, ['то', 'ма'], true)) { |
160
|
|
|
$man += 0.01; |
161
|
|
|
} |
162
|
279 |
View Code Duplication |
if (in_array($last3, ['лья', 'вва', 'ока', 'ука', 'ита'], true)) { |
|
|
|
|
163
|
2 |
|
$man += 0.2; |
164
|
|
|
} |
165
|
279 |
|
if (in_array($last3, ['има'], true)) { |
166
|
|
|
$woman += 0.15; |
167
|
|
|
} |
168
|
279 |
View Code Duplication |
if (in_array($last3, ['лия', 'ния', 'сия', 'дра', 'лла', 'кла', 'опа'], true)) { |
|
|
|
|
169
|
3 |
|
$woman += 0.5; |
170
|
|
|
} |
171
|
279 |
|
if (in_array(S::slice($name, -4), ['льда', 'фира', 'нина', 'лита', 'алья'], true)) { |
|
|
|
|
172
|
|
|
$woman += 0.5; |
173
|
|
|
} |
174
|
|
|
|
175
|
279 |
|
return $man === $woman ? null |
176
|
279 |
|
: ($man > $woman ? self::MALE : self::FEMALE); |
177
|
|
|
} |
178
|
|
|
|
179
|
|
|
/** |
180
|
|
|
* @param string $name |
181
|
|
|
* @param null|string $gender |
182
|
|
|
* @return array |
183
|
|
|
*/ |
184
|
140 |
|
public static function getCases($name, $gender = null) |
185
|
|
|
{ |
186
|
140 |
|
$name = S::lower($name); |
187
|
|
|
|
188
|
140 |
|
if (self::isMutable($name, $gender)) { |
|
|
|
|
189
|
|
|
// common rules for ия and я |
190
|
140 |
|
if (S::slice($name, -2) == 'ия') { |
|
|
|
|
191
|
20 |
|
$prefix = S::name(S::slice($name, 0, -1)); |
|
|
|
|
192
|
|
|
return [ |
193
|
20 |
|
self::IMENIT => $prefix.'я', |
194
|
20 |
|
self::RODIT => $prefix.'и', |
195
|
20 |
|
self::DAT => $prefix.'и', |
196
|
20 |
|
self::VINIT => $prefix.'ю', |
197
|
20 |
|
self::TVORIT => $prefix.'ей', |
198
|
20 |
|
self::PREDLOJ => $prefix.'и', |
199
|
|
|
]; |
200
|
120 |
View Code Duplication |
} elseif (S::slice($name, -1) == 'я') { |
|
|
|
|
201
|
10 |
|
$prefix = S::name(S::slice($name, 0, -1)); |
|
|
|
|
202
|
|
|
return [ |
203
|
10 |
|
self::IMENIT => $prefix.'я', |
204
|
10 |
|
self::RODIT => $prefix.'и', |
205
|
10 |
|
self::DAT => $prefix.'е', |
206
|
10 |
|
self::VINIT => $prefix.'ю', |
207
|
10 |
|
self::TVORIT => $prefix.'ей', |
208
|
10 |
|
self::PREDLOJ => $prefix.'е', |
209
|
|
|
]; |
210
|
|
|
} |
211
|
|
|
|
212
|
110 |
|
if (!in_array($name, self::$immutableNames, true)) { |
213
|
110 |
|
if ($gender === null) { |
214
|
|
|
$gender = self::detectGender($name); |
215
|
|
|
} |
216
|
110 |
|
if ($gender === self::MALE || $name === 'саша') { |
217
|
84 |
|
if (($result = self::getCasesMan($name)) !== null) { |
|
|
|
|
218
|
84 |
|
return $result; |
219
|
|
|
} |
220
|
26 |
|
} elseif ($gender === self::FEMALE) { |
221
|
26 |
|
if (($result = self::getCasesWoman($name)) !== null) { |
|
|
|
|
222
|
26 |
|
return $result; |
223
|
|
|
} |
224
|
|
|
} |
225
|
|
|
} |
226
|
|
|
} |
227
|
|
|
|
228
|
|
|
$name = S::name($name); |
229
|
|
|
return array_fill_keys(array(self::IMENIT, self::RODIT, self::DAT, self::VINIT, self::TVORIT, self::PREDLOJ), $name); |
230
|
|
|
} |
231
|
|
|
|
232
|
|
|
/** |
233
|
|
|
* @param string $name |
234
|
|
|
* @return array|null |
235
|
|
|
*/ |
236
|
84 |
|
protected static function getCasesMan($name) |
237
|
|
|
{ |
238
|
|
|
// special cases for Лев, Павел |
239
|
84 |
|
if (isset(self::$exceptions[$name])) { |
240
|
|
|
return self::$exceptions[$name]; |
241
|
84 |
|
} elseif (in_array(S::slice($name, -1), array_diff(self::$consonants, ['й', /*'Ч', 'Щ'*/]), true)) { // hard consonant |
242
|
24 |
|
if (in_array(S::slice($name, -2), ['ек', 'ёк'], true)) { // Витек, Санек |
243
|
|
|
// case for foreign names like Салмонбек |
244
|
6 |
|
if (self::isConsonant(S::slice($name, -4, -3))) |
245
|
2 |
|
$prefix = S::name(S::slice($name, 0, -2)).'ек'; |
246
|
|
|
else |
247
|
6 |
|
$prefix = S::name(S::slice($name, 0, -2)).'ьк'; |
248
|
|
|
} else { |
249
|
18 |
|
if ($name === 'пётр') |
250
|
|
|
$prefix = S::name(str_replace('ё', 'е', $name)); |
251
|
|
|
else |
252
|
18 |
|
$prefix = S::name($name); |
253
|
|
|
} |
254
|
|
|
return [ |
255
|
24 |
|
self::IMENIT => S::name($name), |
256
|
24 |
|
self::RODIT => $prefix.'а', |
257
|
24 |
|
self::DAT => $prefix.'у', |
258
|
24 |
|
self::VINIT => $prefix.'а', |
259
|
24 |
|
self::TVORIT => RussianLanguage::isHissingConsonant(S::slice($name, -1)) || S::slice($name, -1) == 'ц' ? $prefix.'ем' : $prefix.'ом', |
260
|
24 |
|
self::PREDLOJ => $prefix.'е', |
261
|
|
|
]; |
262
|
60 |
View Code Duplication |
} elseif (S::slice($name, -1) == 'ь' && self::isConsonant(S::slice($name, -2, -1))) { // soft consonant |
|
|
|
|
263
|
10 |
|
$prefix = S::name(S::slice($name, 0, -1)); |
264
|
|
|
return [ |
265
|
10 |
|
self::IMENIT => $prefix.'ь', |
266
|
10 |
|
self::RODIT => $prefix.'я', |
267
|
10 |
|
self::DAT => $prefix.'ю', |
268
|
10 |
|
self::VINIT => $prefix.'я', |
269
|
10 |
|
self::TVORIT => $prefix.'ем', |
270
|
10 |
|
self::PREDLOJ => $prefix.'е', |
271
|
|
|
]; |
272
|
50 |
|
} elseif (in_array(S::slice($name, -2), ['ай', 'ей', 'ой', 'уй', 'яй', 'юй', 'ий'], true)) { |
273
|
24 |
|
$prefix = S::name(S::slice($name, 0, -1)); |
274
|
24 |
|
$postfix = S::slice($name, -2) == 'ий' ? 'и' : 'е'; |
275
|
|
|
return [ |
276
|
24 |
|
self::IMENIT => $prefix.'й', |
277
|
24 |
|
self::RODIT => $prefix.'я', |
278
|
24 |
|
self::DAT => $prefix.'ю', |
279
|
24 |
|
self::VINIT => $prefix.'я', |
280
|
24 |
|
self::TVORIT => $prefix.'ем', |
281
|
24 |
|
self::PREDLOJ => $prefix.$postfix, |
282
|
|
|
]; |
283
|
26 |
|
} elseif (S::slice($name, -1) == 'а' && self::isConsonant($before = S::slice($name, -2, -1)) && !in_array($before, [/*'г', 'к', 'х', */'ц'], true)) { |
284
|
22 |
|
$prefix = S::name(S::slice($name, 0, -1)); |
285
|
22 |
|
$postfix = (RussianLanguage::isHissingConsonant($before) || in_array($before, ['г', 'к', 'х'], true)) ? 'и' : 'ы'; |
286
|
|
|
return [ |
287
|
22 |
|
self::IMENIT => $prefix.'а', |
288
|
22 |
|
self::RODIT => $prefix.$postfix, |
289
|
22 |
|
self::DAT => $prefix.'е', |
290
|
22 |
|
self::VINIT => $prefix.'у', |
291
|
22 |
|
self::TVORIT => $prefix.($before === 'ш' ? 'е' : 'о').'й', |
292
|
22 |
|
self::PREDLOJ => $prefix.'е', |
293
|
|
|
]; |
294
|
4 |
|
} elseif (S::slice($name, -2) == 'ло' || S::slice($name, -2) == 'ко') { |
295
|
4 |
|
$prefix = S::name(S::slice($name, 0, -1)); |
296
|
4 |
|
$postfix = S::slice($name, -2, -1) == 'к' ? 'и' : 'ы'; |
297
|
|
|
return [ |
298
|
4 |
|
self::IMENIT => $prefix.'о', |
299
|
4 |
|
self::RODIT => $prefix.$postfix, |
300
|
4 |
|
self::DAT => $prefix.'е', |
301
|
4 |
|
self::VINIT => $prefix.'у', |
302
|
4 |
|
self::TVORIT => $prefix.'ой', |
303
|
4 |
|
self::PREDLOJ => $prefix.'е', |
304
|
|
|
]; |
305
|
|
|
} |
306
|
|
|
|
307
|
|
|
return null; |
308
|
|
|
} |
309
|
|
|
|
310
|
|
|
/** |
311
|
|
|
* @param string $name |
312
|
|
|
* @return array|null |
313
|
|
|
*/ |
314
|
26 |
|
protected static function getCasesWoman($name) |
315
|
|
|
{ |
316
|
26 |
|
if (S::slice($name, -1) == 'а' && !self::isVowel($before = (S::slice($name, -2, -1)))) { |
317
|
17 |
|
$prefix = S::name(S::slice($name, 0, -1)); |
318
|
17 |
|
if ($before != 'ц') { |
319
|
14 |
|
$postfix = (RussianLanguage::isHissingConsonant($before) || in_array($before, ['г', 'к', 'х'], true)) ? 'и' : 'ы'; |
320
|
|
|
return [ |
321
|
14 |
|
self::IMENIT => $prefix.'а', |
322
|
14 |
|
self::RODIT => $prefix.$postfix, |
323
|
14 |
|
self::DAT => $prefix.'е', |
324
|
14 |
|
self::VINIT => $prefix.'у', |
325
|
14 |
|
self::TVORIT => $prefix.'ой', |
326
|
14 |
|
self::PREDLOJ => $prefix.'е', |
327
|
|
|
]; |
328
|
|
View Code Duplication |
} else { |
|
|
|
|
329
|
|
|
return [ |
330
|
3 |
|
self::IMENIT => $prefix.'а', |
331
|
3 |
|
self::RODIT => $prefix.'ы', |
332
|
3 |
|
self::DAT => $prefix.'е', |
333
|
3 |
|
self::VINIT => $prefix.'у', |
334
|
3 |
|
self::TVORIT => $prefix.'ей', |
335
|
3 |
|
self::PREDLOJ => $prefix.'е', |
336
|
|
|
]; |
337
|
|
|
} |
338
|
9 |
View Code Duplication |
} elseif (S::slice($name, -1) == 'ь' && self::isConsonant(S::slice($name, -2, -1))) { |
|
|
|
|
339
|
4 |
|
$prefix = S::name(S::slice($name, 0, -1)); |
340
|
|
|
return [ |
341
|
4 |
|
self::IMENIT => $prefix.'ь', |
342
|
4 |
|
self::RODIT => $prefix.'и', |
343
|
4 |
|
self::DAT => $prefix.'и', |
344
|
4 |
|
self::VINIT => $prefix.'ь', |
345
|
4 |
|
self::TVORIT => $prefix.'ью', |
346
|
4 |
|
self::PREDLOJ => $prefix.'и', |
347
|
|
|
]; |
348
|
5 |
|
} elseif (RussianLanguage::isHissingConsonant(S::slice($name, -1))) { |
349
|
5 |
|
$prefix = S::name($name); |
350
|
|
|
return [ |
351
|
5 |
|
self::IMENIT => $prefix, |
352
|
5 |
|
self::RODIT => $prefix.'и', |
353
|
5 |
|
self::DAT => $prefix.'и', |
354
|
5 |
|
self::VINIT => $prefix, |
355
|
5 |
|
self::TVORIT => $prefix.'ью', |
356
|
5 |
|
self::PREDLOJ => $prefix.'и', |
357
|
|
|
]; |
358
|
|
|
} |
359
|
|
|
return null; |
360
|
|
|
} |
361
|
|
|
|
362
|
|
|
/** |
363
|
|
|
* @param string $name |
364
|
|
|
* @param string $case |
365
|
|
|
* @param null|string $gender |
366
|
|
|
* @return string |
367
|
|
|
* @throws \Exception |
368
|
|
|
*/ |
369
|
52 |
|
public static function getCase($name, $case, $gender = null) |
370
|
|
|
{ |
371
|
52 |
|
$case = self::canonizeCase($case); |
372
|
52 |
|
$forms = self::getCases($name, $gender); |
373
|
52 |
|
return $forms[$case]; |
374
|
|
|
} |
375
|
|
|
} |
376
|
|
|
|
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:
If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.