1 | <?php |
||||
2 | |||||
3 | namespace Foolz\SphinxQL\Drivers; |
||||
4 | |||||
5 | use Foolz\SphinxQL\Exception\DatabaseException; |
||||
6 | |||||
7 | class MultiResultSet implements MultiResultSetInterface |
||||
8 | { |
||||
9 | /** |
||||
10 | * @var null|array |
||||
11 | */ |
||||
12 | protected $stored; |
||||
13 | |||||
14 | /** |
||||
15 | * @var int |
||||
16 | */ |
||||
17 | protected $cursor = 0; |
||||
18 | |||||
19 | /** |
||||
20 | * @var int |
||||
21 | */ |
||||
22 | protected $next_cursor = 0; |
||||
23 | |||||
24 | /** |
||||
25 | * @var ResultSetInterface|null |
||||
26 | */ |
||||
27 | protected $rowSet; |
||||
28 | |||||
29 | /** |
||||
30 | * @var MultiResultSetAdapterInterface |
||||
31 | */ |
||||
32 | protected $adapter; |
||||
33 | |||||
34 | /** |
||||
35 | * @var bool |
||||
36 | */ |
||||
37 | protected $valid = true; |
||||
38 | |||||
39 | /** |
||||
40 | * @param MultiResultSetAdapterInterface $adapter |
||||
41 | */ |
||||
42 | public function __construct(MultiResultSetAdapterInterface $adapter) |
||||
43 | { |
||||
44 | $this->adapter = $adapter; |
||||
45 | } |
||||
46 | |||||
47 | /** |
||||
48 | * @inheritdoc |
||||
49 | * @throws DatabaseException |
||||
50 | */ |
||||
51 | public function getStored() |
||||
52 | { |
||||
53 | $this->store(); |
||||
54 | |||||
55 | return $this->stored; |
||||
56 | } |
||||
57 | |||||
58 | /** |
||||
59 | * @inheritdoc |
||||
60 | * @throws DatabaseException |
||||
61 | */ |
||||
62 | #[\ReturnTypeWillChange] |
||||
63 | public function offsetExists($offset) |
||||
64 | { |
||||
65 | $this->store(); |
||||
66 | |||||
67 | return $this->storedValid($offset); |
||||
68 | } |
||||
69 | |||||
70 | /** |
||||
71 | * @inheritdoc |
||||
72 | * @throws DatabaseException |
||||
73 | */ |
||||
74 | #[\ReturnTypeWillChange] |
||||
75 | public function offsetGet($offset) |
||||
76 | { |
||||
77 | $this->store(); |
||||
78 | |||||
79 | return $this->stored[$offset]; |
||||
80 | } |
||||
81 | |||||
82 | /** |
||||
83 | * @inheritdoc |
||||
84 | * @codeCoverageIgnore |
||||
85 | */ |
||||
86 | #[\ReturnTypeWillChange] |
||||
87 | public function offsetSet($offset, $value) |
||||
88 | { |
||||
89 | throw new \BadMethodCallException('Not implemented'); |
||||
90 | } |
||||
91 | |||||
92 | /** |
||||
93 | * @inheritdoc |
||||
94 | * @codeCoverageIgnore |
||||
95 | */ |
||||
96 | #[\ReturnTypeWillChange] |
||||
97 | public function offsetUnset($offset) |
||||
98 | { |
||||
99 | throw new \BadMethodCallException('Not implemented'); |
||||
100 | } |
||||
101 | |||||
102 | /** |
||||
103 | * @inheritdoc |
||||
104 | */ |
||||
105 | #[\ReturnTypeWillChange] |
||||
106 | public function next() |
||||
107 | { |
||||
108 | $this->rowSet = $this->getNext(); |
||||
0 ignored issues
–
show
|
|||||
109 | } |
||||
110 | |||||
111 | /** |
||||
112 | * @inheritdoc |
||||
113 | */ |
||||
114 | #[\ReturnTypeWillChange] |
||||
115 | public function key() |
||||
116 | { |
||||
117 | return (int)$this->cursor; |
||||
118 | } |
||||
119 | |||||
120 | /** |
||||
121 | * @inheritdoc |
||||
122 | */ |
||||
123 | #[\ReturnTypeWillChange] |
||||
124 | public function rewind() |
||||
125 | { |
||||
126 | // we actually can't roll this back unless it was stored first |
||||
127 | $this->cursor = 0; |
||||
128 | $this->next_cursor = 0; |
||||
129 | $this->rowSet = $this->getNext(); |
||||
0 ignored issues
–
show
It seems like
$this->getNext() can also be of type false . However, the property $rowSet is declared as type Foolz\SphinxQL\Drivers\ResultSetInterface|null . Maybe add an additional type check?
Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly. For example, imagine you have a variable Either this assignment is in error or a type check should be added for that assignment. class Id
{
public $id;
public function __construct($id)
{
$this->id = $id;
}
}
class Account
{
/** @var Id $id */
public $id;
}
$account_id = false;
if (starsAreRight()) {
$account_id = new Id(42);
}
$account = new Account();
if ($account instanceof Id)
{
$account->id = $account_id;
}
![]() |
|||||
130 | } |
||||
131 | |||||
132 | /** |
||||
133 | * @inheritdoc |
||||
134 | * @throws DatabaseException |
||||
135 | */ |
||||
136 | #[\ReturnTypeWillChange] |
||||
137 | public function count() |
||||
138 | { |
||||
139 | $this->store(); |
||||
140 | |||||
141 | return count($this->stored); |
||||
0 ignored issues
–
show
It seems like
$this->stored can also be of type null ; however, parameter $value of count() does only seem to accept Countable|array , maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||
142 | } |
||||
143 | |||||
144 | /** |
||||
145 | * @inheritdoc |
||||
146 | */ |
||||
147 | #[\ReturnTypeWillChange] |
||||
148 | public function valid() |
||||
149 | { |
||||
150 | if ($this->stored !== null) { |
||||
151 | return $this->storedValid(); |
||||
152 | } |
||||
153 | |||||
154 | return $this->adapter->valid(); |
||||
155 | } |
||||
156 | |||||
157 | /** |
||||
158 | * @inheritdoc |
||||
159 | */ |
||||
160 | #[\ReturnTypeWillChange] |
||||
161 | public function current() |
||||
162 | { |
||||
163 | $rowSet = $this->rowSet; |
||||
164 | unset($this->rowSet); |
||||
165 | |||||
166 | return $rowSet; |
||||
167 | } |
||||
168 | |||||
169 | /** |
||||
170 | * @param null|int $cursor |
||||
171 | * |
||||
172 | * @return bool |
||||
173 | */ |
||||
174 | protected function storedValid($cursor = null) |
||||
175 | { |
||||
176 | $cursor = (!is_null($cursor) ? $cursor : $this->cursor); |
||||
177 | |||||
178 | return $cursor >= 0 && $cursor < count($this->stored); |
||||
0 ignored issues
–
show
It seems like
$this->stored can also be of type null ; however, parameter $value of count() does only seem to accept Countable|array , maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||
179 | } |
||||
180 | |||||
181 | /** |
||||
182 | * @inheritdoc |
||||
183 | */ |
||||
184 | public function getNext() |
||||
185 | { |
||||
186 | $this->cursor = $this->next_cursor; |
||||
187 | |||||
188 | if ($this->stored !== null) { |
||||
189 | $resultSet = !$this->storedValid() ? false : $this->stored[$this->cursor]; |
||||
190 | } else { |
||||
191 | if ($this->next_cursor > 0) { |
||||
192 | $this->adapter->getNext(); |
||||
193 | } |
||||
194 | |||||
195 | $resultSet = !$this->adapter->valid() ? false : $this->adapter->current(); |
||||
196 | } |
||||
197 | |||||
198 | $this->next_cursor++; |
||||
199 | |||||
200 | return $resultSet; |
||||
201 | } |
||||
202 | |||||
203 | /** |
||||
204 | * @inheritdoc |
||||
205 | */ |
||||
206 | public function store() |
||||
207 | { |
||||
208 | if ($this->stored !== null) { |
||||
209 | return $this; |
||||
210 | } |
||||
211 | |||||
212 | // don't let users mix storage and driver cursors |
||||
213 | if ($this->next_cursor > 0) { |
||||
214 | throw new DatabaseException('The MultiResultSet is using the driver cursors, store() can\'t fetch all the data'); |
||||
215 | } |
||||
216 | |||||
217 | $store = array(); |
||||
218 | while ($set = $this->getNext()) { |
||||
219 | // this relies on stored being null! |
||||
220 | $store[] = $set->store(); |
||||
221 | } |
||||
222 | |||||
223 | $this->cursor = 0; |
||||
224 | $this->next_cursor = 0; |
||||
225 | |||||
226 | // if we write the array straight to $this->stored it won't be null anymore and functions relying on null will break |
||||
227 | $this->stored = $store; |
||||
228 | |||||
229 | return $this; |
||||
230 | } |
||||
231 | } |
||||
232 |
Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.
For example, imagine you have a variable
$accountId
that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to theid
property of an instance of theAccount
class. This class holds a proper account, so the id value must no longer be false.Either this assignment is in error or a type check should be added for that assignment.