Issues (12)

src/NoDuplicateLettersStringCombinations.php (11 issues)

1
<?php
2
3
namespace BenTools\StringCombinations;
4
5
use Countable;
6
use Generator;
7
use IteratorAggregate;
8
use Traversable;
9
10
final class NoDuplicateLettersStringCombinations implements IteratorAggregate, Countable
11
{
12
    private StringCombinations $stringCombinations;
13
14
    public function __construct(StringCombinations $stringCombinations)
15
    {
16
        $this->stringCombinations = $stringCombinations;
17
    }
18
19
    public function getIterator(): Traversable
20
    {
21
        for ($i = $this->stringCombinations->min; $i <= $this->stringCombinations->max; $i++) {
0 ignored issues
show
Bug Best Practice introduced by
The property $max is declared private in BenTools\StringCombinations\StringCombinations. Since you implement __get, consider adding a @property or @property-read.
Loading history...
Bug Best Practice introduced by
The property $min is declared private in BenTools\StringCombinations\StringCombinations. Since you implement __get, consider adding a @property or @property-read.
Loading history...
22
            foreach ($this->permute($this->stringCombinations->charset, $i) as $combination) {
0 ignored issues
show
Bug Best Practice introduced by
The property $charset is declared private in BenTools\StringCombinations\StringCombinations. Since you implement __get, consider adding a @property or @property-read.
Loading history...
23
                yield implode($this->stringCombinations->glue, $combination);
0 ignored issues
show
Bug Best Practice introduced by
The property $glue is declared private in BenTools\StringCombinations\StringCombinations. Since you implement __get, consider adding a @property or @property-read.
Loading history...
24
            }
25
        }
26
    }
27
28
    public function count(): int
29
    {
30
        $arr = [];
31
32
        for ($pos = $this->stringCombinations->max, $i = 0; $pos >= $this->stringCombinations->min; $pos--, $i++) {
0 ignored issues
show
Bug Best Practice introduced by
The property $max is declared private in BenTools\StringCombinations\StringCombinations. Since you implement __get, consider adding a @property or @property-read.
Loading history...
Bug Best Practice introduced by
The property $min is declared private in BenTools\StringCombinations\StringCombinations. Since you implement __get, consider adding a @property or @property-read.
Loading history...
33
            if (0 === $i) {
34
                $arr[$i] = [$pos];
35
            } else {
36
                $arr[$i] = array_merge($arr[$i - 1], [$pos]);
37
            }
38
        }
39
40
        return array_sum(array_map('array_product', $arr));
0 ignored issues
show
Bug Best Practice introduced by
The expression return array_sum(array_m...'array_product', $arr)) could return the type double which is incompatible with the type-hinted return integer. Consider adding an additional type-check to rule them out.
Loading history...
41
    }
42
43
    private function permute(array $charset, $length = null): Generator
44
    {
45
        $n = count($charset);
46
47
        if (null === $length) {
48
            $length = $n;
49
        }
50
51
        if ($length > $n) {
52
            return;
53
        }
54
55
        $indices = range(0, $n - 1);
56
        $cycles = range($n, $n - $length + 1, -1);
57
58
        yield array_slice($charset, 0, $length);
59
60
        if ($n <= 0) {
61
            return;
62
        }
63
64
        while (true) {
65
            $exitEarly = false;
66
            for ($i = $length; $i--;) {
67
                $cycles[$i]-= 1;
68
                if ($cycles[$i] == 0) {
69
                    if ($i < count($indices)) {
70
                        $removed = array_splice($indices, $i, 1);
71
                        $indices[] = $removed[0];
72
                    }
73
                    $cycles[$i] = $n - $i;
74
                } else {
75
                    $j = $cycles[$i];
76
                    $value = $indices[$i];
77
                    $negative = $indices[count($indices) - $j];
78
                    $indices[$i] = $negative;
79
                    $indices[count($indices) - $j] = $value;
80
                    $result = [];
81
                    $counter = 0;
82
                    foreach ($indices as $index) {
83
                        $result[] = $charset[$index];
84
                        $counter++;
85
                        if ($counter == $length) {
86
                            break;
87
                        }
88
                    }
89
                    yield $result;
90
                    $exitEarly = true;
91
                    break;
92
                }
93
            }
94
            if (!$exitEarly) {
95
                break;
96
            }
97
        }
98
    }
99
100
    public function getRandomString(): string
101
    {
102
        $charset = $this->stringCombinations->charset;
0 ignored issues
show
Bug Best Practice introduced by
The property $charset is declared private in BenTools\StringCombinations\StringCombinations. Since you implement __get, consider adding a @property or @property-read.
Loading history...
103
        $string = [];
104
105
        $length = random_int($this->stringCombinations->min, $this->stringCombinations->max);
0 ignored issues
show
Bug Best Practice introduced by
The property $max is declared private in BenTools\StringCombinations\StringCombinations. Since you implement __get, consider adding a @property or @property-read.
Loading history...
Bug Best Practice introduced by
The property $min is declared private in BenTools\StringCombinations\StringCombinations. Since you implement __get, consider adding a @property or @property-read.
Loading history...
106
107
        for ($pos = 1; $pos <= $length; $pos++) {
108
            shuffle($charset);
109
110
            $string[] = array_shift($charset);
111
        }
112
113
        return implode($this->stringCombinations->glue, $string);
0 ignored issues
show
Bug Best Practice introduced by
The property $glue is declared private in BenTools\StringCombinations\StringCombinations. Since you implement __get, consider adding a @property or @property-read.
Loading history...
114
    }
115
116
    public function asArray(): array
117
    {
118
        return iterator_to_array($this);
119
    }
120
}
121