FirstNamesInflection::detectGender()   F
last analyzed

Complexity

Conditions 16
Paths 8194

Size

Total Lines 53

Duplication

Lines 6
Ratio 11.32 %

Code Coverage

Tests 29
CRAP Score 16.8148

Importance

Changes 0
Metric Value
cc 16
nc 8194
nop 1
dl 6
loc 53
ccs 29
cts 34
cp 0.8529
crap 16.8148
rs 1.4
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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))) {
0 ignored issues
show
Bug introduced by wapmorgan
It seems like $name defined by \morphos\S::lower($name) on line 82 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...
96 14
                return true;
97 437
            } elseif (in_array(S::slice($name, -1), array_diff(self::$consonants, ['й', /*'Ч', 'Щ'*/]), true)) { // hard consonant
0 ignored issues
show
Bug introduced by wapmorgan
It seems like $name defined by \morphos\S::lower($name) on line 82 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...
98 259
                return true;
99 178
            } elseif (S::slice($name, -1) == 'й') {
0 ignored issues
show
Bug introduced by wapmorgan
It seems like $name defined by \morphos\S::lower($name) on line 82 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...
100 104
                return true;
101 74 View Code Duplication
            } else if (in_array(S::slice($name, -2), ['ло', 'ко'], true)) {
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...
Bug introduced by wapmorgan
It seems like $name defined by \morphos\S::lower($name) on line 82 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...
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))) {
0 ignored issues
show
Bug introduced by wapmorgan
It seems like $name defined by \morphos\S::lower($name) on line 82 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...
107 4
                return true;
108 261
            } else if (self::isHissingConsonant(S::slice($name, -1))) {
0 ignored issues
show
Bug introduced by wapmorgan
It seems like $name defined by \morphos\S::lower($name) on line 82 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...
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)) {
0 ignored issues
show
Bug introduced by wapmorgan
It seems like $name defined by \morphos\S::lower($name) on line 82 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 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);
0 ignored issues
show
Bug introduced by wapmorgan
It seems like $name defined by \morphos\S::lower($name) on line 127 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 279
        $last2 = S::slice($name, -2);
0 ignored issues
show
Bug introduced by wapmorgan
It seems like $name defined by \morphos\S::lower($name) on line 127 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...
137 279
        $last3 = S::slice($name, -3);
0 ignored issues
show
Bug introduced by wapmorgan
It seems like $name defined by \morphos\S::lower($name) on line 127 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...
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)) {
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...
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)) {
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...
169 3
            $woman += 0.5;
170
        }
171 279
        if (in_array(S::slice($name, -4), ['льда', 'фира', 'нина', 'лита', 'алья'], true)) {
0 ignored issues
show
Bug introduced by wapmorgan
It seems like $name defined by \morphos\S::lower($name) on line 127 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...
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)) {
0 ignored issues
show
Bug introduced by wapmorgan
It seems like $name defined by \morphos\S::lower($name) on line 186 can also be of type boolean; however, morphos\Russian\FirstNamesInflection::isMutable() 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
            // common rules for ия and я
190 140
            if (S::slice($name, -2) == 'ия') {
0 ignored issues
show
Bug introduced by wapmorgan
It seems like $name defined by \morphos\S::lower($name) on line 186 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...
191 20
                $prefix = S::name(S::slice($name, 0, -1));
0 ignored issues
show
Bug introduced by wapmorgan
It seems like $name defined by \morphos\S::lower($name) on line 186 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...
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) == 'я') {
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...
Bug introduced by wapmorgan
It seems like $name defined by \morphos\S::lower($name) on line 186 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...
201 10
                $prefix = S::name(S::slice($name, 0, -1));
0 ignored issues
show
Bug introduced by wapmorgan
It seems like $name defined by \morphos\S::lower($name) on line 186 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...
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) {
0 ignored issues
show
Bug introduced by wapmorgan
It seems like $name defined by \morphos\S::lower($name) on line 186 can also be of type boolean; however, morphos\Russian\FirstNam...flection::getCasesMan() 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 84
                        return $result;
219
                    }
220 26
                } elseif ($gender === self::FEMALE) {
221 26
                    if (($result = self::getCasesWoman($name)) !== null) {
0 ignored issues
show
Bug introduced by wapmorgan
It seems like $name defined by \morphos\S::lower($name) on line 186 can also be of type boolean; however, morphos\Russian\FirstNam...ection::getCasesWoman() 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...
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
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...
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 {
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...
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))) {
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 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