1
|
|
|
<?php |
2
|
|
|
namespace morphos\Russian; |
3
|
|
|
|
4
|
|
|
use morphos\BaseInflection; |
5
|
|
|
use morphos\Gender; |
6
|
|
|
use morphos\S; |
7
|
|
|
|
8
|
|
|
/** |
9
|
|
|
* Class AdjectiveDeclension. |
10
|
|
|
* |
11
|
|
|
* Склонение прилагательных. |
12
|
|
|
* |
13
|
|
|
* Правила склонения: |
14
|
|
|
* - http://www.fio.ru/pravila/grammatika/sklonenie-prilagatelnykh-v-russkom-yazyke/ |
15
|
|
|
* |
16
|
|
|
* @package morphos\Russian |
17
|
|
|
*/ |
18
|
|
|
class AdjectiveDeclension extends BaseInflection implements Cases, Gender |
19
|
|
|
{ |
20
|
|
|
use RussianLanguage, CasesHelper; |
21
|
|
|
|
22
|
|
|
const HARD_BASE = 1; |
23
|
|
|
const SOFT_BASE = 2; |
24
|
|
|
const MIXED_BASE = 3; |
25
|
|
|
|
26
|
|
|
/** |
27
|
|
|
* @param string $adjective |
28
|
|
|
* @return bool|void |
29
|
|
|
*/ |
30
|
|
|
public static function isMutable($adjective) |
31
|
|
|
{ |
32
|
|
|
return false; |
33
|
|
|
} |
34
|
|
|
|
35
|
|
|
/** |
36
|
|
|
* @param string $adjective |
37
|
|
|
* @param string $case |
38
|
|
|
* @param bool $animateness |
39
|
|
|
* @param null $gender |
40
|
|
|
* |
41
|
|
|
* @return string |
42
|
|
|
* @throws \Exception |
43
|
|
|
*/ |
44
|
|
|
public static function getCase($adjective, $case, $animateness = false, $gender = null) |
45
|
|
|
{ |
46
|
|
|
$case = static::canonizeCase($case); |
47
|
|
|
|
48
|
|
|
if ($gender === null) |
49
|
|
|
$gender = static::detectGender($adjective); |
50
|
|
|
|
51
|
|
|
$forms = static::getCases($adjective, $animateness, $gender); |
52
|
|
|
return $forms[$case]; |
53
|
|
|
} |
54
|
|
|
|
55
|
|
|
/** |
56
|
|
|
* @param $adjective |
57
|
|
|
* |
58
|
|
|
* @param bool $isEmphasized |
59
|
|
|
* |
60
|
|
|
* @return string |
61
|
|
|
*/ |
62
|
24 |
|
public static function detectGender($adjective, &$isEmphasized = false) |
63
|
|
|
{ |
64
|
24 |
|
switch (S::lower(S::slice($adjective, -2))) |
65
|
|
|
{ |
66
|
24 |
|
case 'ой': |
67
|
4 |
|
$isEmphasized = true; |
68
|
20 |
|
case 'ый': |
69
|
19 |
|
case 'ий': |
70
|
8 |
|
return static::MALE; |
71
|
|
|
|
72
|
16 |
|
case 'ая': |
73
|
10 |
|
case 'яя': |
74
|
8 |
|
return static::FEMALE; |
75
|
|
|
|
76
|
8 |
|
case 'ое': |
77
|
2 |
|
case 'ее': |
78
|
8 |
|
return static::NEUTER; |
79
|
|
|
} |
80
|
|
|
} |
81
|
|
|
|
82
|
|
|
/** |
83
|
|
|
* @param string $adjective |
84
|
|
|
* @param bool $animateness |
85
|
|
|
* @param null|string $gender |
86
|
|
|
* |
87
|
|
|
* @return array |
88
|
|
|
*/ |
89
|
18 |
|
public static function getCases($adjective, $animateness = false, $gender = null) |
90
|
|
|
{ |
91
|
18 |
|
if ($gender === null) |
92
|
18 |
|
$gender = static::detectGender($adjective, $isEmphasized); |
93
|
|
|
|
94
|
18 |
|
$last_consonant_vowel = S::slice($adjective, -2, -1); |
95
|
18 |
|
$type = static::getAdjectiveBaseType($adjective); |
96
|
18 |
|
$adjective = S::slice($adjective, 0, -2); |
97
|
|
|
|
98
|
|
|
switch ($type) |
99
|
|
|
{ |
100
|
18 |
|
case static::HARD_BASE: |
101
|
6 |
|
return static::declinateHardAdjective($adjective, $animateness, $gender, |
|
|
|
|
102
|
6 |
|
$last_consonant_vowel); |
103
|
|
|
|
104
|
12 |
|
case static::SOFT_BASE: |
105
|
3 |
|
return static::declinateSoftAdjective($adjective, $animateness, $gender, |
|
|
|
|
106
|
3 |
|
$last_consonant_vowel); |
107
|
|
|
|
108
|
9 |
|
case static::MIXED_BASE: |
109
|
9 |
|
return static::declinateMixedAdjective($adjective, $animateness, $gender, |
|
|
|
|
110
|
9 |
|
$last_consonant_vowel); |
111
|
|
|
} |
112
|
|
|
} |
113
|
|
|
|
114
|
|
|
/** |
115
|
|
|
* @param $adjective |
116
|
|
|
* |
117
|
|
|
* @return int |
118
|
|
|
*/ |
119
|
19 |
|
public static function getAdjectiveBaseType($adjective) |
120
|
|
|
{ |
121
|
19 |
|
$adjective = S::lower($adjective); |
122
|
19 |
|
$consonants = static::$consonants; |
123
|
|
|
|
124
|
19 |
|
unset($consonants[array_search('н', $consonants)]); |
125
|
19 |
|
unset($consonants[array_search('й', $consonants)]); |
126
|
|
|
|
127
|
19 |
|
$substring = S::findLastPositionForOneOfChars($adjective, $consonants); |
128
|
19 |
|
$last_consonant = S::slice($substring, 0, 1); |
|
|
|
|
129
|
|
|
|
130
|
|
|
// г, к, х, ударное ш - признак смешанного прилагательно |
131
|
19 |
|
if (in_array($last_consonant, ['г', 'к', 'х'], true) || |
132
|
|
|
( |
133
|
19 |
|
$last_consonant === 'ш' && in_array(S::slice($substring, 1, 2), ['о', 'а'], true) |
|
|
|
|
134
|
|
|
)) { |
135
|
9 |
|
return static::MIXED_BASE; |
136
|
|
|
} |
137
|
|
|
|
138
|
10 |
|
return static::checkBaseLastConsonantSoftness($substring) |
139
|
10 |
|
|| (S::slice($substring, 0, 2) === 'шн') |
|
|
|
|
140
|
3 |
|
? static::SOFT_BASE |
141
|
10 |
|
: static::HARD_BASE; |
142
|
|
|
} |
143
|
|
|
|
144
|
|
|
/** |
145
|
|
|
* @param string $adjective |
146
|
|
|
* @param bool $animateness |
147
|
|
|
* @param string $gender |
148
|
|
|
* @param bool $isEmphasized |
|
|
|
|
149
|
|
|
* |
150
|
|
|
* @param $afterConsonantVowel |
151
|
|
|
* |
152
|
|
|
* @return array |
153
|
|
|
*/ |
154
|
6 |
View Code Duplication |
protected static function declinateHardAdjective($adjective, $animateness, $gender, |
|
|
|
|
155
|
|
|
$afterConsonantVowel) |
156
|
|
|
{ |
157
|
|
|
switch ($gender) |
158
|
|
|
{ |
159
|
6 |
|
case static::MALE: |
160
|
2 |
|
$postfix = $afterConsonantVowel.'й'; |
161
|
2 |
|
break; |
162
|
|
|
|
163
|
4 |
|
case static::FEMALE: |
164
|
2 |
|
$postfix = $afterConsonantVowel.'я'; |
165
|
2 |
|
break; |
166
|
|
|
|
167
|
2 |
|
case static::NEUTER: |
168
|
2 |
|
$postfix = $afterConsonantVowel.'е'; |
169
|
2 |
|
break; |
170
|
|
|
} |
171
|
|
|
|
172
|
|
|
$cases = [ |
173
|
6 |
|
static::IMENIT => $adjective.$postfix, |
|
|
|
|
174
|
6 |
|
static::RODIT => $adjective.'о'.($gender !== static::FEMALE ? 'го' : 'й'), |
175
|
6 |
|
static::DAT => $adjective.'о'.($gender !== static::FEMALE ? 'му' : 'й'), |
176
|
|
|
]; |
177
|
|
|
|
178
|
6 |
|
if ($gender !== static::FEMALE) |
179
|
4 |
|
$cases[static::VINIT] = static::getVinitCaseByAnimateness($cases, $animateness); |
180
|
|
|
else |
181
|
2 |
|
$cases[static::VINIT] = $adjective.'ую'; |
182
|
|
|
|
183
|
6 |
|
$cases[static::TVORIT] = $adjective.($gender !== static::FEMALE ? 'ым' : 'ой'); |
184
|
6 |
|
$cases[static::PREDLOJ] = $adjective.($gender !== static::FEMALE ? 'ом' : 'ой'); |
185
|
|
|
|
186
|
6 |
|
return $cases; |
187
|
|
|
} |
188
|
|
|
|
189
|
|
|
/** |
190
|
|
|
* @param string $adjective |
191
|
|
|
* @param bool $animateness |
192
|
|
|
* @param string $gender |
193
|
|
|
* @param bool $isEmphasized |
|
|
|
|
194
|
|
|
* |
195
|
|
|
* @param $afterConsonantVowel |
196
|
|
|
* |
197
|
|
|
* @return array |
198
|
|
|
*/ |
199
|
3 |
View Code Duplication |
protected static function declinateSoftAdjective($adjective, $animateness, $gender, $afterConsonantVowel) |
|
|
|
|
200
|
|
|
{ |
201
|
|
|
switch ($gender) |
202
|
|
|
{ |
203
|
3 |
|
case static::MALE: |
204
|
1 |
|
$postfix = $afterConsonantVowel.'й'; |
205
|
1 |
|
break; |
206
|
|
|
|
207
|
2 |
|
case static::FEMALE: |
208
|
1 |
|
$postfix = $afterConsonantVowel.'я'; |
209
|
1 |
|
break; |
210
|
|
|
|
211
|
1 |
|
case static::NEUTER: |
212
|
1 |
|
$postfix = $afterConsonantVowel.'е'; |
213
|
1 |
|
break; |
214
|
|
|
} |
215
|
|
|
|
216
|
|
|
$cases = [ |
217
|
3 |
|
static::IMENIT => $adjective.$postfix, |
|
|
|
|
218
|
3 |
|
static::RODIT => $adjective.'е'.($gender !== static::FEMALE ? 'го' : 'й'), |
219
|
3 |
|
static::DAT => $adjective.'е'.($gender !== static::FEMALE ? 'му' : 'й'), |
220
|
|
|
]; |
221
|
|
|
|
222
|
3 |
|
if ($gender !== static::FEMALE) |
223
|
2 |
|
$cases[static::VINIT] = static::getVinitCaseByAnimateness($cases, $animateness); |
224
|
|
|
else |
225
|
1 |
|
$cases[static::VINIT] = $adjective.'юю'; |
226
|
|
|
|
227
|
3 |
|
$cases[static::TVORIT] = $adjective.($gender !== static::FEMALE ? 'им' : 'ей'); |
228
|
3 |
|
$cases[static::PREDLOJ] = $adjective.($gender !== static::FEMALE ? 'ем' : 'ей'); |
229
|
|
|
|
230
|
3 |
|
return $cases; |
231
|
|
|
} |
232
|
|
|
|
233
|
|
|
/** |
234
|
|
|
* @param string $adjective |
235
|
|
|
* @param bool $animateness |
236
|
|
|
* @param string $gender |
237
|
|
|
* @param bool $isEmphasized |
|
|
|
|
238
|
|
|
* |
239
|
|
|
* @return array |
240
|
|
|
*/ |
241
|
9 |
|
protected static function declinateMixedAdjective($adjective, $animateness, $gender, $afterConsonantVowel) |
242
|
|
|
{ |
243
|
|
|
switch ($gender) |
244
|
|
|
{ |
245
|
9 |
|
case static::MALE: |
246
|
3 |
|
$postfix = $afterConsonantVowel.'й'; |
247
|
3 |
|
break; |
248
|
|
|
|
249
|
6 |
|
case static::FEMALE: |
250
|
3 |
|
$postfix = $afterConsonantVowel.'я'; |
251
|
3 |
|
break; |
252
|
|
|
|
253
|
3 |
|
case static::NEUTER: |
254
|
3 |
|
$postfix = $afterConsonantVowel.'е'; |
255
|
3 |
|
break; |
256
|
|
|
} |
257
|
|
|
|
258
|
|
|
$cases = [ |
259
|
9 |
|
static::IMENIT => $adjective.$postfix, |
|
|
|
|
260
|
9 |
|
static::RODIT => $adjective.'о'.($gender !== static::FEMALE ? 'го' : 'й'), |
261
|
9 |
|
static::DAT => $adjective.'о'.($gender !== static::FEMALE ? 'му' : 'й'), |
262
|
|
|
]; |
263
|
|
|
|
264
|
9 |
|
if ($gender === static::MALE) |
265
|
3 |
|
$cases[static::VINIT] = static::getVinitCaseByAnimateness($cases, $animateness); |
266
|
6 |
|
else if ($gender === static::NEUTER) |
267
|
3 |
|
$cases[static::VINIT] = $adjective.'ое'; |
268
|
|
|
else |
269
|
3 |
|
$cases[static::VINIT] = $adjective.'ую'; |
270
|
|
|
|
271
|
9 |
|
$cases[static::TVORIT] = $adjective.($gender !== static::FEMALE ? 'им' : 'ой'); |
272
|
9 |
|
$cases[static::PREDLOJ] = $adjective.($gender !== static::FEMALE ? 'ом' : 'ой'); |
273
|
|
|
|
274
|
9 |
|
return $cases; |
275
|
|
|
} |
276
|
|
|
} |
This check looks for type mismatches where the missing type is
false
. This is usually indicative of an error condtion.Consider the follow example
This function either returns a new
DateTime
object or false, if there was an error. This is a typical pattern in PHP programming to show that an error has occurred without raising an exception. The calling code should check for this returnedfalse
before passing on the value to another function or method that may not be able to handle afalse
.