NounDeclension   F
last analyzed

Complexity

Total Complexity 68

Size/Duplication

Total Lines 434
Duplicated Lines 9.22 %

Coupling/Cohesion

Components 1
Dependencies 4

Test Coverage

Coverage 96.82%

Importance

Changes 0
Metric Value
dl 40
loc 434
ccs 152
cts 157
cp 0.9682
rs 2.96
c 0
b 0
f 0
wmc 68
lcom 1
cbo 4

11 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 48 13
A declinateThirdDeclension() 0 13 1
B declinateAdjective() 28 53 9
A getCase() 0 6 1
B getPrefixOfSecondDeclension() 6 20 7
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\BaseInflection;
5
use morphos\Gender;
6
use morphos\S;
7
8
/**
9
 * Rules are from http://morpher.ru/Russian/Noun.aspx
10
 */
11
class NounDeclension extends BaseInflection implements Cases, Gender
12
{
13
    use RussianLanguage, CasesHelper;
14
15
    const FIRST_DECLENSION = 1;
16
    const SECOND_DECLENSION = 2;
17
    const THIRD_DECLENSION = 3;
18
19
    public static $immutableWords = [
20
        // валюты
21
        'евро', 'пенни', 'песо', 'сентаво',
22
23
        // на а
24
        'боа', 'бра', 'фейхоа', 'амплуа', 'буржуа',
25
        // на о
26
        'манго', 'какао', 'кино', 'трюмо', 'пальто', 'бюро', 'танго', 'вето', 'бунгало', 'сабо', 'авокадо', 'депо', 'панно',
27
        // на у
28
        'зебу', 'кенгуру', 'рагу', 'какаду', 'шоу',
29
        // на е
30
        'шимпанзе', 'конферансье', 'атташе', 'колье', 'резюме', 'пенсне', 'кашне', 'протеже', 'коммюнике', 'драже', 'суфле', 'пюре', 'купе', 'фойе', 'шоссе', 'крупье',
31
        // на и
32
        'такси', 'жалюзи', 'шасси', 'алиби', 'киви', 'иваси', 'регби', 'конфетти', 'колибри', 'жюри', 'пенальти', 'рефери', 'кольраби',
33
        // на э
34
        'каноэ', 'алоэ',
35
        // на ю
36
        'меню', 'парвеню', 'авеню', 'дежавю', 'инженю', 'барбекю', 'интервью',
37
    ];
38
39
    /**
40
     * These words has 2 declension type.
41
     */
42
    protected static $abnormalExceptions = [
43
        'бремя',
44
        'вымя',
45
        'темя',
46
        'пламя',
47
        'стремя',
48
        'пламя',
49
        'время',
50
        'знамя',
51
        'имя',
52
        'племя',
53
        'семя',
54
        'путь' => ['путь', 'пути', 'пути', 'путь', 'путем', 'пути'],
55
        'дитя' => ['дитя', 'дитяти', 'дитяти', 'дитя', 'дитятей', 'дитяти'],
56
    ];
57
58
    protected static $masculineWithSoft = [
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
    ];
90
91
    protected static $masculineWithSoftAndRunAwayVowels = [
92
        'день',
93
        'пень',
94
        'парень',
95
        'камень',
96
        'корень',
97
        'трутень',
98
    ];
99
100
    /**
101
     * Проверка, изменяемое ли слово.
102
     * @param string $word Слово для проверки
103
     * @param bool $animateness Признак одушевленности
104
     * @return bool
105
     */
106 43
    public static function isMutable($word, $animateness = false)
0 ignored issues
show
Unused Code introduced by wapmorgan
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...
107
    {
108 43
        $word = S::lower($word);
109 43
        if (in_array(S::slice($word, -1), ['у', 'и', 'е', 'о', 'ю'], true) || in_array($word, static::$immutableWords, true)) {
0 ignored issues
show
Bug introduced by wapmorgan
It seems like $word defined by \morphos\S::lower($word) on line 108 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...
110 43
            return false;
111
        }
112
        return true;
113
    }
114
115
    /**
116
     * Определение рода существительного.
117
     * @param string $word
118
     * @return string
119
     */
120 8
    public static function detectGender($word)
121
    {
122 8
    	$word = S::lower($word);
123 8
    	$last = S::slice($word, -1);
0 ignored issues
show
Bug introduced by wapmorgan
It seems like $word defined by \morphos\S::lower($word) on line 122 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...
124
		// пытаемся угадать род объекта, хотя бы примерно, чтобы правильно склонять
125 8
		if (S::slice($word, -2) == 'мя' || in_array($last, ['о', 'е', 'и', 'у'], true))
0 ignored issues
show
Bug introduced by wapmorgan
It seems like $word defined by \morphos\S::lower($word) on line 122 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...
126 2
			return static::NEUTER;
127
128 6
		if (in_array($last, ['а', 'я'], true) ||
129 6
			($last == 'ь' && !in_array($word, static::$masculineWithSoft, true) && !in_array($word, static::$masculineWithSoftAndRunAwayVowels, true)))
130 3
			return static::FEMALE;
131
132 3
		return static::MALE;
133
    }
134
135
    /**
136
     * Определение склонения (по школьной программе) существительного.
137
     * @param $word
138
     * @param bool $animateness
139
     * @return int
140
     */
141 186
    public static function getDeclension($word, $animateness = false)
0 ignored issues
show
Unused Code introduced by wapmorgan
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...
142
    {
143 186
        $word = S::lower($word);
144 186
        $last = S::slice($word, -1);
0 ignored issues
show
Bug introduced by wapmorgan
It seems like $word defined by \morphos\S::lower($word) on line 143 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...
145 186
        if (isset(static::$abnormalExceptions[$word]) || in_array($word, static::$abnormalExceptions, true)) {
146 3
            return 2;
147
        }
148
149 183
        if (in_array($last, ['а', 'я'], true) && S::slice($word, -2) != 'мя') {
0 ignored issues
show
Bug introduced by wapmorgan
It seems like $word defined by \morphos\S::lower($word) on line 143 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...
150 58
            return 1;
151 134
        } elseif (static::isConsonant($last) || in_array($last, ['о', 'е', 'ё'], true)
152 35
            || ($last == 'ь' && static::isConsonant(S::slice($word, -2, -1)) && !static::isHissingConsonant(S::slice($word, -2, -1))
0 ignored issues
show
Bug introduced by wapmorgan
It seems like $word defined by \morphos\S::lower($word) on line 143 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...
153 134
                && (in_array($word, static::$masculineWithSoft, true)) || in_array($word, static::$masculineWithSoftAndRunAwayVowels, true))) {
154 125
            return 2;
155
        } else {
156 9
            return 3;
157
        }
158
    }
159
160
    /**
161
     * Получение слова во всех 6 падежах.
162
     * @param string $word
163
     * @param bool $animateness Признак одушевлённости
164
     * @return array
165
     */
166 104
    public static function getCases($word, $animateness = false)
167
    {
168 104
        $word = S::lower($word);
169
170
        // Адъективное склонение (Сущ, образованные от прилагательных и причастий) - прохожий, существительное
171 104
        if (static::isAdjectiveNoun($word)) {
0 ignored issues
show
Bug introduced by wapmorgan
It seems like $word defined by \morphos\S::lower($word) on line 168 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...
172 8
            return static::declinateAdjective($word, $animateness);
173
        }
174
175
        // Субстантивное склонение (существительные)
176 96
        if (in_array($word, static::$immutableWords, true)) {
177
            return [
178 3
                static::IMENIT => $word,
179 3
                static::RODIT => $word,
180 3
                static::DAT => $word,
181 3
                static::VINIT => $word,
182 3
                static::TVORIT => $word,
183 3
                static::PREDLOJ => $word,
184
            ];
185 93
        } elseif (isset(static::$abnormalExceptions[$word])) {
186 2
            return array_combine([static::IMENIT, static::RODIT, static::DAT, static::VINIT, static::TVORIT, static::PREDLOJ], static::$abnormalExceptions[$word]);
187 91
        } elseif (in_array($word, static::$abnormalExceptions, true)) {
188 1
            $prefix = S::slice($word, 0, -1);
0 ignored issues
show
Bug introduced by wapmorgan
It seems like $word defined by \morphos\S::lower($word) on line 168 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...
189
            return [
190 1
                static::IMENIT => $word,
191 1
                static::RODIT => $prefix.'ени',
192 1
                static::DAT => $prefix.'ени',
193 1
                static::VINIT => $word,
194 1
                static::TVORIT => $prefix.'енем',
195 1
                static::PREDLOJ => $prefix.'ени',
196
            ];
197
        }
198
199 90
        switch (static::getDeclension($word)) {
200 90
            case static::FIRST_DECLENSION:
201 25
                return static::declinateFirstDeclension($word);
202 67
            case static::SECOND_DECLENSION:
203 63
                return static::declinateSecondDeclension($word, $animateness);
204 4
            case static::THIRD_DECLENSION:
205 4
                return static::declinateThirdDeclension($word);
206
        }
207
    }
208
209
    /**
210
     * Получение всех форм слова первого склонения.
211
     * @param $word
212
     * @return array
213
     */
214 25
    public static function declinateFirstDeclension($word)
215
    {
216 25
        $word = S::lower($word);
217 25
        $prefix = S::slice($word, 0, -1);
0 ignored issues
show
Bug introduced by wapmorgan
It seems like $word defined by \morphos\S::lower($word) on line 216 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...
218 25
        $last = S::slice($word, -1);
0 ignored issues
show
Bug introduced by wapmorgan
It seems like $word defined by \morphos\S::lower($word) on line 216 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...
219 25
        $soft_last = static::checkLastConsonantSoftness($word);
220
        $forms =  [
221 25
            Cases::IMENIT => $word,
222
        ];
223
224
        // RODIT
225 25
        $forms[Cases::RODIT] = static::chooseVowelAfterConsonant($last, $soft_last || (in_array(S::slice($word, -2, -1), ['г', 'к', 'х'], true)), $prefix.'и', $prefix.'ы');
0 ignored issues
show
Bug introduced by wapmorgan
It seems like $word defined by \morphos\S::lower($word) on line 216 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...
226
227
        // DAT
228 25
        $forms[Cases::DAT] = static::getPredCaseOf12Declensions($word, $last, $prefix);
229
230
        // VINIT
231 25
        $forms[Cases::VINIT] = static::chooseVowelAfterConsonant($last, $soft_last && S::slice($word, -2, -1) !== 'ч', $prefix.'ю', $prefix.'у');
0 ignored issues
show
Bug introduced by wapmorgan
It seems like $word defined by \morphos\S::lower($word) on line 216 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...
232
233
        // TVORIT
234 25
        if ($last === 'ь') {
235
            $forms[Cases::TVORIT] = $prefix.'ой';
236 View Code Duplication
        } else {
0 ignored issues
show
Duplication introduced by wapmorgan
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...
237 25
            $forms[Cases::TVORIT] = static::chooseVowelAfterConsonant($last, $soft_last, $prefix.'ей', $prefix.'ой');
238
        }
239
240
        // 	if ($last == 'й' || (static::isConsonant($last) && !static::isHissingConsonant($last)) || static::checkLastConsonantSoftness($word))
241
        // 	$forms[Cases::TVORIT] = $prefix.'ей';
242
        // else
243
        // 	$forms[Cases::TVORIT] = $prefix.'ой'; # http://morpher.ru/Russian/Spelling.aspx#sibilant
244
245
        // PREDLOJ the same as DAT
246 25
        $forms[Cases::PREDLOJ] = $forms[Cases::DAT];
247 25
        return $forms;
248
    }
249
250
    /**
251
     * Получение всех форм слова второго склонения.
252
     * @param $word
253
     * @param bool $animateness
254
     * @return array
255
     */
256 63
    public static function declinateSecondDeclension($word, $animateness = false)
257
    {
258 63
        $word = S::lower($word);
259 63
        $last = S::slice($word, -1);
0 ignored issues
show
Bug introduced by wapmorgan
It seems like $word defined by \morphos\S::lower($word) on line 258 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...
260 63
        $soft_last = $last === 'й' || (in_array($last, ['ь', 'е', 'ё', 'ю', 'я'], true)
261
            && ((
262 23
                static::isConsonant(S::slice($word, -2, -1)) && !static::isHissingConsonant(S::slice($word, -2, -1)))
0 ignored issues
show
Bug introduced by wapmorgan
It seems like $word defined by \morphos\S::lower($word) on line 258 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...
263 63
                    || S::slice($word, -2, -1) === 'и'));
0 ignored issues
show
Bug introduced by wapmorgan
It seems like $word defined by \morphos\S::lower($word) on line 258 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...
264 63
        $prefix = static::getPrefixOfSecondDeclension($word, $last);
265
        $forms =  [
266 63
            Cases::IMENIT => $word,
267
        ];
268
269
        // RODIT
270 63
        $forms[Cases::RODIT] = static::chooseVowelAfterConsonant($last, $soft_last, $prefix.'я', $prefix.'а');
271
272
        // DAT
273 63
        $forms[Cases::DAT] = static::chooseVowelAfterConsonant($last, $soft_last, $prefix.'ю', $prefix.'у');
274
275
        // VINIT
276 63
        if (in_array($last, ['о', 'е', 'ё'], true)) {
277 13
            $forms[Cases::VINIT] = $word;
278
        } else {
279 50
            $forms[Cases::VINIT] = static::getVinitCaseByAnimateness($forms, $animateness);
280
        }
281
282
        // TVORIT
283
        // if ($last == 'ь')
284
        // 	$forms[Cases::TVORIT] = $prefix.'ом';
285
        // else if ($last == 'й' || (static::isConsonant($last) && !static::isHissingConsonant($last)))
286
        // 	$forms[Cases::TVORIT] = $prefix.'ем';
287
        // else
288
        // 	$forms[Cases::TVORIT] = $prefix.'ом'; # http://morpher.ru/Russian/Spelling.aspx#sibilant
289 63
        if (static::isHissingConsonant($last)
290 61
            || (in_array($last, ['ь', 'е', 'ё', 'ю', 'я'], true) && static::isHissingConsonant(S::slice($word, -2, -1)))
0 ignored issues
show
Bug introduced by wapmorgan
It seems like $word defined by \morphos\S::lower($word) on line 258 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...
291 63
            || ($last === 'ц' && S::slice($word, -2) !== 'ец')) {
0 ignored issues
show
Bug introduced by wapmorgan
It seems like $word defined by \morphos\S::lower($word) on line 258 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...
292 5
            $forms[Cases::TVORIT] = $prefix.'ем';
293 58 View Code Duplication
        } elseif (in_array($last, ['й'/*, 'ч', 'щ'*/], true) || $soft_last) {
0 ignored issues
show
Duplication introduced by wapmorgan
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...
294 24
            $forms[Cases::TVORIT] = $prefix.'ем';
295
        } else {
296 34
            $forms[Cases::TVORIT] = $prefix.'ом';
297
        }
298
299
        // PREDLOJ
300 63
        $forms[Cases::PREDLOJ] = static::getPredCaseOf12Declensions($word, $last, $prefix);
301
302 63
        return $forms;
303
    }
304
305
    /**
306
     * Получение всех форм слова третьего склонения.
307
     * @param $word
308
     * @return array
309
     */
310 4
    public static function declinateThirdDeclension($word)
311
    {
312 4
        $word = S::lower($word);
313 4
        $prefix = S::slice($word, 0, -1);
0 ignored issues
show
Bug introduced by wapmorgan
It seems like $word defined by \morphos\S::lower($word) on line 312 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...
314
        return [
315 4
            Cases::IMENIT => $word,
316 4
            Cases::RODIT => $prefix.'и',
317 4
            Cases::DAT => $prefix.'и',
318 4
            Cases::VINIT => $word,
319 4
            Cases::TVORIT => $prefix.'ью',
320 4
            Cases::PREDLOJ => $prefix.'и',
321
        ];
322
    }
323
324
    /**
325
     * Склонение существительных, образованных от прилагательных и причастий.
326
     * Rules are from http://rusgram.narod.ru/1216-1231.html
327
     * @param $word
328
     * @param $animateness
329
     * @return array
330
     */
331 8
    public static function declinateAdjective($word, $animateness)
0 ignored issues
show
Unused Code introduced by wapmorgan
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...
332
    {
333 8
        $prefix = S::slice($word, 0, -2);
334
335 8
        switch (S::slice($word, -2)) {
336
            // Male adjectives
337 8
            case 'ой':
338 7 View Code Duplication
            case 'ый':
0 ignored issues
show
Duplication introduced by wapmorgan
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...
339
                return [
340 2
                    Cases::IMENIT => $word,
341 2
                    Cases::RODIT => $prefix.'ого',
342 2
                    Cases::DAT => $prefix.'ому',
343 2
                    Cases::VINIT => $word,
344 2
                    Cases::TVORIT => $prefix.'ым',
345 2
                    Cases::PREDLOJ => $prefix.'ом',
346
                ];
347
348 6 View Code Duplication
            case 'ий':
0 ignored issues
show
Duplication introduced by wapmorgan
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...
349
                return [
350 1
                    Cases::IMENIT => $word,
351 1
                    Cases::RODIT => $prefix.'его',
352 1
                    Cases::DAT => $prefix.'ему',
353 1
                    Cases::VINIT => $prefix.'его',
354 1
                    Cases::TVORIT => $prefix.'им',
355 1
                    Cases::PREDLOJ => $prefix.'ем',
356
                ];
357
358
            // Neuter adjectives
359 5
            case 'ое':
360 4 View Code Duplication
            case 'ее':
0 ignored issues
show
Duplication introduced by wapmorgan
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...
361 2
                $prefix = S::slice($word, 0, -1);
362
                return [
363 2
                    Cases::IMENIT => $word,
364 2
                    Cases::RODIT => $prefix.'го',
365 2
                    Cases::DAT => $prefix.'му',
366 2
                    Cases::VINIT => $word,
367 2
                    Cases::TVORIT => S::slice($word, 0, -2).(S::slice($word, -2, -1) == 'о' ? 'ы' : 'и').'м',
368 2
                    Cases::PREDLOJ => $prefix.'м',
369
                ];
370
371
            // Female adjectives
372 3
            case 'ая':
373 3
                $ending = static::isHissingConsonant(S::slice($prefix, -1)) ? 'ей' : 'ой';
0 ignored issues
show
Security Bug introduced by wapmorgan
It seems like $prefix defined by \morphos\S::slice($word, 0, -2) on line 333 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...
374
                return [
375 3
                    Cases::IMENIT => $word,
376 3
                    Cases::RODIT => $prefix.$ending,
377 3
                    Cases::DAT => $prefix.$ending,
378 3
                    Cases::VINIT => $prefix.'ую',
379 3
                    Cases::TVORIT => $prefix.$ending,
380 3
                    Cases::PREDLOJ => $prefix.$ending,
381
                ];
382
        }
383
    }
384
385
    /**
386
     * Получение одной формы слова (падежа).
387
     * @param string $word Слово
388
     * @param integer $case Падеж
389
     * @param bool $animateness Признак одушевленности
390
     * @return string
391
     * @throws \Exception
392
     */
393 41
    public static function getCase($word, $case, $animateness = false)
394
    {
395 41
        $case = static::canonizeCase($case);
396 41
        $forms = static::getCases($word, $animateness);
397 41
        return $forms[$case];
398
    }
399
400
    /**
401
     * @param $word
402
     * @param $last
403
     * @return bool
404
     */
405 93
    public static function getPrefixOfSecondDeclension($word, $last)
406
    {
407
        // слова с бегающей гласной в корне
408 93
        if (in_array($word, static::$masculineWithSoftAndRunAwayVowels, true)) {
409 7
            $prefix = S::slice($word, 0, -3).S::slice($word, -2, -1);
410 88
        } elseif (in_array($last, ['о', 'е', 'ё', 'ь', 'й'], true)) {
411 34
            $prefix = S::slice($word, 0, -1);
412
        }
413
        // уменьшительные формы слов (котенок) и слова с суффиксом ок
414 54 View Code Duplication
        elseif (S::slice($word, -2) === 'ок' && S::length($word) > 3) {
0 ignored issues
show
Duplication introduced by wapmorgan
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...
415 4
            $prefix = S::slice($word, 0, -2) . 'к';
416
        }
417
        // слова с суффиксом бец
418 50 View Code Duplication
        elseif (S::slice($word, -3) === 'бец' && S::length($word) > 4) {
0 ignored issues
show
Duplication introduced by wapmorgan
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...
419 1
            $prefix = S::slice($word, 0, -3).'бц';
420
        } else {
421 49
            $prefix = $word;
422
        }
423 93
        return $prefix;
424
    }
425
426
    /**
427
     * @param $word
428
     * @param $last
429
     * @param $prefix
430
     * @return string
431
     */
432 86
    public static function getPredCaseOf12Declensions($word, $last, $prefix)
433
    {
434 86
        if (in_array(S::slice($word, -2), ['ий', 'ие'], true)) {
435 6
            if ($last == 'ё') {
436
                return $prefix.'е';
437
            } else {
438 6
                return $prefix.'и';
439
            }
440
        } else {
441 80
            return $prefix.'е';
442
        }
443
    }
444
}
445