Completed
Push — master ( 38f7c0...210f74 )
by f
01:42
created

NounDeclension   F

Complexity

Total Complexity 67

Size/Duplication

Total Lines 434
Duplicated Lines 7.83 %

Coupling/Cohesion

Components 1
Dependencies 4

Test Coverage

Coverage 96.82%

Importance

Changes 0
Metric Value
dl 34
loc 434
ccs 152
cts 157
cp 0.9682
rs 3.04
c 0
b 0
f 0
wmc 67
lcom 1
cbo 4

12 Methods

Rating   Name   Duplication   Size   Complexity  
A isMutable() 0 8 3
B detectGender() 0 14 7
C getDeclension() 0 18 12
B getCases() 0 42 8
A declinateFirstDeclension() 3 35 4
C declinateSecondDeclension() 3 46 12
A declinateThirdDeclension() 0 13 1
B declinateAdjective() 28 53 9
A getCase() 0 6 1
A getPrefixOfSecondDeclension() 0 16 5
A getVinitCaseByAnimateness() 0 8 2
A getPredCaseOf12Declensions() 0 12 3

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like NounDeclension often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use NounDeclension, and based on these observations, apply Extract Interface, too.

1
<?php
2
namespace morphos\Russian;
3
4
use morphos\Gender;
5
use morphos\S;
6
7
/**
8
 * Rules are from http://morpher.ru/Russian/Noun.aspx
9
 */
10
class NounDeclension extends \morphos\BaseInflection implements Cases, Gender
11
{
12
    use RussianLanguage, CasesHelper;
13
14
    const FIRST_DECLENSION = 1;
15
    const SECOND_DECLENSION = 2;
16
    const THIRD_DECLENSION = 3;
17
18
    /**
19
     * These words has 2 declension type.
20
     */
21
    protected static $abnormalExceptions = [
22
        'бремя',
23
        'вымя',
24
        'темя',
25
        'пламя',
26
        'стремя',
27
        'пламя',
28
        'время',
29
        'знамя',
30
        'имя',
31
        'племя',
32
        'семя',
33
        'путь' => ['путь', 'пути', 'пути', 'путь', 'путем', 'пути'],
34
        'дитя' => ['дитя', 'дитяти', 'дитяти', 'дитя', 'дитятей', 'дитяти'],
35
    ];
36
37
    protected static $masculineWithSoft = [
38
        'ячмень',
39
        'путь',
40
        'шкворень',
41
        'пельмень',
42
        'табель',
43
        'рояль',
44
        'шампунь',
45
        'гвоздь',
46
        'рубль',
47
        'дождь',
48
        'зверь',
49
        'юань',
50
        'олень',
51
        'конь',
52
        'конь',
53
        'лось',
54
        'тюлень',
55
        'выхухоль',
56
        'медведь',
57
        'председатель',
58
        'руководитель',
59
        'заместитель',
60
    ];
61
62
    protected static $masculineWithSoftAndRunAwayVowels = [
63
        'день',
64
        'пень',
65
        'парень',
66
        'камень',
67
        'корень',
68
        'трутень',
69
    ];
70
71
    protected static $immutableWords = [
72
        // валюты
73
        'евро', 'пенни', 'песо', 'сентаво',
74
75
        // на а
76
        'боа', 'бра', 'фейхоа', 'амплуа', 'буржуа',
77
        // на о
78
        'манго', 'какао', 'кино', 'трюмо', 'пальто', 'бюро', 'танго', 'вето', 'бунгало', 'сабо', 'авокадо', 'депо',
79
        // на у
80
        'зебу', 'кенгуру', 'рагу', 'какаду', 'шоу',
81
        // на е
82
        'шимпанзе', 'конферансье', 'атташе', 'колье', 'резюме', 'пенсне', 'кашне', 'протеже', 'коммюнике', 'драже', 'суфле', 'пюре', 'купе', 'фойе', 'шоссе',
83
        // на и
84
        'такси', 'жалюзи', 'шасси', 'алиби', 'киви', 'иваси', 'регби', 'конфетти', 'колибри', 'жюри', 'пенальти', 'рефери', 'кольраби',
85
        // на э
86
        'каноэ', 'алоэ',
87
        // на ю
88
        'меню', 'парвеню', 'авеню', 'дежавю', 'инженю', 'барбекю', 'интервью',
89
    ];
90
91
    /**
92
     * Проверка, изменяемое ли слово.
93
     * @param string $word Слово для проверки
94
     * @param bool $animateness Признак одушевленности
95
     * @return bool
96
     */
97 43
    public static function isMutable($word, $animateness = false)
0 ignored issues
show
Unused Code introduced by
The parameter $animateness is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
98
    {
99 43
        $word = S::lower($word);
100 43
        if (in_array(S::slice($word, -1), ['у', 'и', 'е', 'о', 'ю'], true) || in_array($word, self::$immutableWords, true)) {
0 ignored issues
show
Bug introduced by
It seems like $word defined by \morphos\S::lower($word) on line 99 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...
101 43
            return false;
102
        }
103
        return true;
104
    }
105
106
    /**
107
     * Определение рода существительного.
108
     * @param string $word
109
     * @return string
110
     */
111 8
    public static function detectGender($word)
112
    {
113 8
    	$word = S::lower($word);
114 8
    	$last = S::slice($word, -1);
0 ignored issues
show
Bug introduced by
It seems like $word defined by \morphos\S::lower($word) on line 113 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...
115
		// пытаемся угадать род объекта, хотя бы примерно, чтобы правильно склонять
116 8
		if (S::slice($word, -2) == 'мя' || in_array($last, ['о', 'е', 'и', 'у'], true))
0 ignored issues
show
Bug introduced by
It seems like $word defined by \morphos\S::lower($word) on line 113 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...
117 2
			return self::NEUTER;
118
119 6
		if (in_array($last, ['а', 'я'], true) ||
120 6
			($last == 'ь' && !in_array($word, self::$masculineWithSoft, true) && !in_array($word, self::$masculineWithSoftAndRunAwayVowels, true)))
121 3
			return self::FEMALE;
122
123 3
		return self::MALE;
124
    }
125
126
    /**
127
     * Определение склонения (по школьной программе) существительного.
128
     * @param $word
129
     * @param bool $animateness
130
     * @return int
131
     */
132 174
    public static function getDeclension($word, $animateness = false)
0 ignored issues
show
Unused Code introduced by
The parameter $animateness is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
133
    {
134 174
        $word = S::lower($word);
135 174
        $last = S::slice($word, -1);
0 ignored issues
show
Bug introduced by
It seems like $word defined by \morphos\S::lower($word) on line 134 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...
136 174
        if (isset(self::$abnormalExceptions[$word]) || in_array($word, self::$abnormalExceptions, true)) {
137 3
            return 2;
138
        }
139
140 171
        if (in_array($last, ['а', 'я'], true) && S::slice($word, -2) != 'мя') {
0 ignored issues
show
Bug introduced by
It seems like $word defined by \morphos\S::lower($word) on line 134 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...
141 56
            return 1;
142 124
        } elseif (self::isConsonant($last) || in_array($last, ['о', 'е', 'ё'], true)
143 32
            || ($last == 'ь' && self::isConsonant(S::slice($word, -2, -1)) && !self::isHissingConsonant(S::slice($word, -2, -1))
0 ignored issues
show
Bug introduced by
It seems like $word defined by \morphos\S::lower($word) on line 134 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...
144 124
                && (in_array($word, self::$masculineWithSoft, true)) || in_array($word, self::$masculineWithSoftAndRunAwayVowels, true))) {
145 115
            return 2;
146
        } else {
147 9
            return 3;
148
        }
149
    }
150
151
    /**
152
     * Получение слова во всех 6 падежах.
153
     * @param string $word
154
     * @param bool $animateness Признак одушевлённости
155
     * @return array
156
     */
157 98
    public static function getCases($word, $animateness = false)
158
    {
159 98
        $word = S::lower($word);
160
161
        // Адъективное склонение (Сущ, образованные от прилагательных и причастий) - прохожий, существительное
162 98
        if (self::isAdjectiveNoun($word)) {
0 ignored issues
show
Bug introduced by
It seems like $word defined by \morphos\S::lower($word) on line 159 can also be of type boolean; however, morphos\Russian\RussianLanguage::isAdjectiveNoun() 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...
163 8
            return self::declinateAdjective($word, $animateness);
164
        }
165
166
        // Субстантивное склонение (существительные)
167 90
        if (in_array($word, self::$immutableWords, true)) {
168
            return [
169 3
                self::IMENIT => $word,
170 3
                self::RODIT => $word,
171 3
                self::DAT => $word,
172 3
                self::VINIT => $word,
173 3
                self::TVORIT => $word,
174 3
                self::PREDLOJ => $word,
175
            ];
176 87
        } elseif (isset(self::$abnormalExceptions[$word])) {
177 2
            return array_combine([self::IMENIT, self::RODIT, self::DAT, self::VINIT, self::TVORIT, self::PREDLOJ], self::$abnormalExceptions[$word]);
178 85
        } elseif (in_array($word, self::$abnormalExceptions, true)) {
179 1
            $prefix = S::slice($word, 0, -1);
0 ignored issues
show
Bug introduced by
It seems like $word defined by \morphos\S::lower($word) on line 159 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...
180
            return [
181 1
                self::IMENIT => $word,
182 1
                self::RODIT => $prefix.'ени',
183 1
                self::DAT => $prefix.'ени',
184 1
                self::VINIT => $word,
185 1
                self::TVORIT => $prefix.'енем',
186 1
                self::PREDLOJ => $prefix.'ени',
187
            ];
188
        }
189
190 84
        switch (self::getDeclension($word)) {
191 84
            case self::FIRST_DECLENSION:
192 25
                return self::declinateFirstDeclension($word);
193 61
            case self::SECOND_DECLENSION:
194 57
                return self::declinateSecondDeclension($word, $animateness);
195 4
            case self::THIRD_DECLENSION:
196 4
                return self::declinateThirdDeclension($word);
197
        }
198
    }
199
200
    /**
201
     * Получение всех форм слова первого склонения.
202
     * @param $word
203
     * @return array
204
     */
205 25
    public static function declinateFirstDeclension($word)
206
    {
207 25
        $word = S::lower($word);
208 25
        $prefix = S::slice($word, 0, -1);
0 ignored issues
show
Bug introduced by
It seems like $word defined by \morphos\S::lower($word) on line 207 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...
209 25
        $last = S::slice($word, -1);
0 ignored issues
show
Bug introduced by
It seems like $word defined by \morphos\S::lower($word) on line 207 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...
210 25
        $soft_last = self::checkLastConsonantSoftness($word);
211
        $forms =  [
212 25
            Cases::IMENIT => $word,
213
        ];
214
215
        // RODIT
216 25
        $forms[Cases::RODIT] = self::chooseVowelAfterConsonant($last, $soft_last || (in_array(S::slice($word, -2, -1), ['г', 'к', 'х'], true)), $prefix.'и', $prefix.'ы');
0 ignored issues
show
Bug introduced by
It seems like $word defined by \morphos\S::lower($word) on line 207 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...
217
218
        // DAT
219 25
        $forms[Cases::DAT] = self::getPredCaseOf12Declensions($word, $last, $prefix);
220
221
        // VINIT
222 25
        $forms[Cases::VINIT] = self::chooseVowelAfterConsonant($last, $soft_last && S::slice($word, -2, -1) != 'ч', $prefix.'ю', $prefix.'у');
0 ignored issues
show
Bug introduced by
It seems like $word defined by \morphos\S::lower($word) on line 207 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...
223
224
        // TVORIT
225 25
        if ($last == 'ь') {
226
            $forms[Cases::TVORIT] = $prefix.'ой';
227 View Code Duplication
        } else {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
228 25
            $forms[Cases::TVORIT] = self::chooseVowelAfterConsonant($last, $soft_last, $prefix.'ей', $prefix.'ой');
229
        }
230
231
        // 	if ($last == 'й' || (self::isConsonant($last) && !self::isHissingConsonant($last)) || self::checkLastConsonantSoftness($word))
232
        // 	$forms[Cases::TVORIT] = $prefix.'ей';
233
        // else
234
        // 	$forms[Cases::TVORIT] = $prefix.'ой'; # http://morpher.ru/Russian/Spelling.aspx#sibilant
235
236
        // PREDLOJ the same as DAT
237 25
        $forms[Cases::PREDLOJ] = $forms[Cases::DAT];
238 25
        return $forms;
239
    }
240
241
    /**
242
     * Получение всех форм слова второго склонения.
243
     * @param $word
244
     * @param bool $animateness
245
     * @return array
246
     */
247 57
    public static function declinateSecondDeclension($word, $animateness = false)
248
    {
249 57
        $word = S::lower($word);
250 57
        $last = S::slice($word, -1);
0 ignored issues
show
Bug introduced by
It seems like $word defined by \morphos\S::lower($word) on line 249 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...
251 57
        $soft_last = $last == 'й' || (in_array($last, ['ь', 'е', 'ё', 'ю', 'я'], true)
252
            && ((
253 21
                self::isConsonant(S::slice($word, -2, -1)) && !self::isHissingConsonant(S::slice($word, -2, -1)))
0 ignored issues
show
Bug introduced by
It seems like $word defined by \morphos\S::lower($word) on line 249 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...
254 57
                    || S::slice($word, -2, -1) == 'и'));
0 ignored issues
show
Bug introduced by
It seems like $word defined by \morphos\S::lower($word) on line 249 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...
255 57
        $prefix = self::getPrefixOfSecondDeclension($word, $last);
256
        $forms =  [
257 57
            Cases::IMENIT => $word,
258
        ];
259
260
        // RODIT
261 57
        $forms[Cases::RODIT] = self::chooseVowelAfterConsonant($last, $soft_last, $prefix.'я', $prefix.'а');
262
263
        // DAT
264 57
        $forms[Cases::DAT] = self::chooseVowelAfterConsonant($last, $soft_last, $prefix.'ю', $prefix.'у');
265
266
        // VINIT
267 57
        if (in_array($last, ['о', 'е', 'ё'], true)) {
268 12
            $forms[Cases::VINIT] = $word;
269
        } else {
270 45
            $forms[Cases::VINIT] = self::getVinitCaseByAnimateness($forms, $animateness);
271
        }
272
273
        // TVORIT
274
        // if ($last == 'ь')
275
        // 	$forms[Cases::TVORIT] = $prefix.'ом';
276
        // else if ($last == 'й' || (self::isConsonant($last) && !self::isHissingConsonant($last)))
277
        // 	$forms[Cases::TVORIT] = $prefix.'ем';
278
        // else
279
        // 	$forms[Cases::TVORIT] = $prefix.'ом'; # http://morpher.ru/Russian/Spelling.aspx#sibilant
280 57
        if (self::isHissingConsonant($last) || (in_array($last, ['ь', 'е', 'ё', 'ю', 'я'], true) && self::isHissingConsonant(S::slice($word, -2, -1))) || $last == 'ц') {
0 ignored issues
show
Bug introduced by
It seems like $word defined by \morphos\S::lower($word) on line 249 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...
281 5
            $forms[Cases::TVORIT] = $prefix.'ем';
282 52 View Code Duplication
        } elseif (in_array($last, ['й'/*, 'ч', 'щ'*/], true) || $soft_last) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
283 22
            $forms[Cases::TVORIT] = $prefix.'ем';
284
        } else {
285 30
            $forms[Cases::TVORIT] = $prefix.'ом';
286
        }
287
288
        // PREDLOJ
289 57
        $forms[Cases::PREDLOJ] = self::getPredCaseOf12Declensions($word, $last, $prefix);
290
291 57
        return $forms;
292
    }
293
294
    /**
295
     * Получение всех форм слова третьего склонения.
296
     * @param $word
297
     * @return array
298
     */
299 4
    public static function declinateThirdDeclension($word)
300
    {
301 4
        $word = S::lower($word);
302 4
        $prefix = S::slice($word, 0, -1);
0 ignored issues
show
Bug introduced by
It seems like $word defined by \morphos\S::lower($word) on line 301 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...
303
        return [
304 4
            Cases::IMENIT => $word,
305 4
            Cases::RODIT => $prefix.'и',
306 4
            Cases::DAT => $prefix.'и',
307 4
            Cases::VINIT => $word,
308 4
            Cases::TVORIT => $prefix.'ью',
309 4
            Cases::PREDLOJ => $prefix.'и',
310
        ];
311
    }
312
313
    /**
314
     * Склонение существительных, образованных от прилагательных и причастий.
315
     * Rules are from http://rusgram.narod.ru/1216-1231.html
316
     * @param $word
317
     * @param $animateness
318
     * @return array
319
     */
320 8
    public static function declinateAdjective($word, $animateness)
0 ignored issues
show
Unused Code introduced by
The parameter $animateness is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
321
    {
322 8
        $prefix = S::slice($word, 0, -2);
323
324 8
        switch (S::slice($word, -2)) {
325
            // Male adjectives
326 8
            case 'ой':
327 7 View Code Duplication
            case 'ый':
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
328
                return [
329 2
                    Cases::IMENIT => $word,
330 2
                    Cases::RODIT => $prefix.'ого',
331 2
                    Cases::DAT => $prefix.'ому',
332 2
                    Cases::VINIT => $word,
333 2
                    Cases::TVORIT => $prefix.'ым',
334 2
                    Cases::PREDLOJ => $prefix.'ом',
335
                ];
336
337 6 View Code Duplication
            case 'ий':
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
338
                return [
339 1
                    Cases::IMENIT => $word,
340 1
                    Cases::RODIT => $prefix.'его',
341 1
                    Cases::DAT => $prefix.'ему',
342 1
                    Cases::VINIT => $prefix.'его',
343 1
                    Cases::TVORIT => $prefix.'им',
344 1
                    Cases::PREDLOJ => $prefix.'ем',
345
                ];
346
347
            // Neuter adjectives
348 5
            case 'ое':
349 4 View Code Duplication
            case 'ее':
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
350 2
                $prefix = S::slice($word, 0, -1);
351
                return [
352 2
                    Cases::IMENIT => $word,
353 2
                    Cases::RODIT => $prefix.'го',
354 2
                    Cases::DAT => $prefix.'му',
355 2
                    Cases::VINIT => $word,
356 2
                    Cases::TVORIT => S::slice($word, 0, -2).(S::slice($word, -2, -1) == 'о' ? 'ы' : 'и').'м',
357 2
                    Cases::PREDLOJ => $prefix.'м',
358
                ];
359
360
            // Female adjectives
361 3
            case 'ая':
362 3
                $ending = self::isHissingConsonant(S::slice($prefix, -1)) ? 'ей' : 'ой';
0 ignored issues
show
Security Bug introduced by
It seems like $prefix defined by \morphos\S::slice($word, 0, -2) on line 322 can also be of type false; however, morphos\S::slice() does only seem to accept string, did you maybe forget to handle an error condition?

This check looks for type mismatches where the missing type is false. This is usually indicative of an error condtion.

Consider the follow example

<?php

function getDate($date)
{
    if ($date !== null) {
        return new DateTime($date);
    }

    return false;
}

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 returned false before passing on the value to another function or method that may not be able to handle a false.

Loading history...
363
                return [
364 3
                    Cases::IMENIT => $word,
365 3
                    Cases::RODIT => $prefix.$ending,
366 3
                    Cases::DAT => $prefix.$ending,
367 3
                    Cases::VINIT => $prefix.'ую',
368 3
                    Cases::TVORIT => $prefix.$ending,
369 3
                    Cases::PREDLOJ => $prefix.$ending,
370
                ];
371
        }
372
    }
373
374
    /**
375
     * Получение одной формы слова (падежа).
376
     * @param string $word Слово
377
     * @param integer $case Падеж
378
     * @param bool $animateness Признак одушевленности
379
     * @return string
380
     * @throws \Exception
381
     */
382 37
    public static function getCase($word, $case, $animateness = false)
383
    {
384 37
        $case = self::canonizeCase($case);
385 37
        $forms = self::getCases($word, $animateness);
386 37
        return $forms[$case];
387
    }
388
389
    /**
390
     * @param $word
391
     * @param $last
392
     * @return bool
393
     */
394 85
    public static function getPrefixOfSecondDeclension($word, $last)
395
    {
396
        // слова с бегающей гласной в корне
397 85
        if (in_array($word, self::$masculineWithSoftAndRunAwayVowels, true)) {
398 7
            $prefix = S::slice($word, 0, -3).S::slice($word, -2, -1);
399 80
        } elseif (in_array($last, ['о', 'е', 'ё', 'ь', 'й'], true)) {
400 32
            $prefix = S::slice($word, 0, -1);
401
        }
402
        // уменьшительные формы слов (котенок) и слова с суффиксом ок
403 48
        elseif (S::slice($word, -2) == 'ок' && S::length($word) > 3) {
404 4
            $prefix = S::slice($word, 0, -2).'к';
405
        } else {
406 44
            $prefix = $word;
407
        }
408 85
        return $prefix;
409
    }
410
411
    /**
412
     * @param array $forms
413
     * @param $animate
414
     * @return mixed
415
     */
416 104
    public static function getVinitCaseByAnimateness(array $forms, $animate)
417
    {
418 104
        if ($animate) {
419 9
            return $forms[Cases::RODIT];
420
        } else {
421 95
            return $forms[Cases::IMENIT];
422
        }
423
    }
424
425
    /**
426
     * @param $word
427
     * @param $last
428
     * @param $prefix
429
     * @return string
430
     */
431 80
    public static function getPredCaseOf12Declensions($word, $last, $prefix)
432
    {
433 80
        if (in_array(S::slice($word, -2), ['ий', 'ие'], true)) {
434 5
            if ($last == 'ё') {
435
                return $prefix.'е';
436
            } else {
437 5
                return $prefix.'и';
438
            }
439
        } else {
440 75
            return $prefix.'е';
441
        }
442
    }
443
}
444