1 | <?php |
||
2 | |||
3 | declare(strict_types=1); |
||
4 | |||
5 | namespace Doctrine\DBAL\Driver; |
||
6 | |||
7 | use Doctrine\DBAL\Driver\Exception\UnknownParamType; |
||
8 | use Doctrine\DBAL\ParameterType; |
||
9 | use PDO; |
||
10 | use Traversable; |
||
11 | use function array_slice; |
||
12 | use function assert; |
||
13 | use function count; |
||
14 | use function func_get_args; |
||
15 | use function is_array; |
||
16 | |||
17 | /** |
||
18 | * The PDO implementation of the Statement interface. |
||
19 | * Used by all PDO-based drivers. |
||
20 | */ |
||
21 | class PDOStatement implements Statement |
||
22 | { |
||
23 | private const PARAM_TYPE_MAP = [ |
||
24 | ParameterType::NULL => PDO::PARAM_NULL, |
||
25 | ParameterType::INTEGER => PDO::PARAM_INT, |
||
26 | ParameterType::STRING => PDO::PARAM_STR, |
||
27 | ParameterType::BINARY => PDO::PARAM_LOB, |
||
28 | ParameterType::LARGE_OBJECT => PDO::PARAM_LOB, |
||
29 | ParameterType::BOOLEAN => PDO::PARAM_BOOL, |
||
30 | ]; |
||
31 | |||
32 | /** @var \PDOStatement */ |
||
33 | private $stmt; |
||
34 | |||
35 | public function __construct(\PDOStatement $stmt) |
||
36 | { |
||
37 | $this->stmt = $stmt; |
||
38 | } |
||
39 | |||
40 | /** |
||
41 | * {@inheritdoc} |
||
42 | */ |
||
43 | public function bindValue($param, $value, int $type = ParameterType::STRING) : void |
||
44 | 4621 | { |
|
45 | $type = $this->convertParamType($type); |
||
46 | 4621 | ||
47 | 4621 | try { |
|
48 | $this->stmt->bindValue($param, $value, $type); |
||
49 | 4384 | } catch (\PDOException $exception) { |
|
50 | throw new PDOException($exception); |
||
51 | 4384 | } |
|
52 | } |
||
53 | |||
54 | 4384 | /** |
|
55 | * @param mixed $param |
||
56 | * @param mixed $variable |
||
57 | * @param mixed $driverOptions |
||
58 | 4384 | */ |
|
59 | public function bindParam($param, &$variable, int $type = ParameterType::STRING, ?int $length = null, $driverOptions = null) : void |
||
60 | { |
||
61 | $type = $this->convertParamType($type); |
||
62 | $extraParameters = array_slice(func_get_args(), 3); |
||
63 | 1631 | ||
64 | if (count($extraParameters) !== 0) { |
||
65 | 1631 | $extraParameters[0] = $extraParameters[0] ?? 0; |
|
66 | } |
||
67 | |||
68 | 1631 | try { |
|
69 | 48 | $this->stmt->bindParam($param, $variable, $type, ...$extraParameters); |
|
70 | } catch (\PDOException $exception) { |
||
71 | throw new PDOException($exception); |
||
72 | 1631 | } |
|
73 | } |
||
74 | |||
75 | public function closeCursor() : void |
||
76 | { |
||
77 | $this->stmt->closeCursor(); |
||
78 | } |
||
79 | 421 | ||
80 | public function columnCount() : int |
||
81 | 421 | { |
|
82 | 421 | return $this->stmt->columnCount(); |
|
83 | } |
||
84 | 421 | ||
85 | 421 | /** |
|
86 | * {@inheritdoc} |
||
87 | */ |
||
88 | public function execute(?array $params = null) : void |
||
89 | 421 | { |
|
90 | 4 | try { |
|
91 | $this->stmt->execute($params); |
||
92 | } catch (\PDOException $exception) { |
||
93 | 421 | throw new PDOException($exception); |
|
94 | } |
||
95 | 247 | } |
|
96 | |||
97 | 247 | public function rowCount() : int |
|
98 | 247 | { |
|
99 | return $this->stmt->rowCount(); |
||
100 | 52 | } |
|
101 | |||
102 | 52 | /** |
|
103 | * {@inheritdoc} |
||
104 | */ |
||
105 | public function fetchNumeric() |
||
106 | { |
||
107 | return $this->fetch(PDO::FETCH_NUM); |
||
108 | 2438 | } |
|
109 | |||
110 | /** |
||
111 | 2438 | * {@inheritdoc} |
|
112 | 89 | */ |
|
113 | 89 | public function fetchAssociative() |
|
114 | { |
||
115 | 2409 | return $this->fetch(PDO::FETCH_ASSOC); |
|
116 | } |
||
117 | 1244 | ||
118 | /** |
||
119 | 1244 | * {@inheritdoc} |
|
120 | */ |
||
121 | public function fetchColumn() |
||
122 | { |
||
123 | return $this->fetch(PDO::FETCH_COLUMN); |
||
124 | } |
||
125 | 1695 | ||
126 | /** |
||
127 | * {@inheritdoc} |
||
128 | 1695 | */ |
|
129 | 91 | public function fetchAllNumeric() : array |
|
130 | { |
||
131 | return $this->fetchAll(PDO::FETCH_NUM); |
||
132 | 1604 | } |
|
133 | 1604 | ||
134 | /** |
||
135 | * {@inheritdoc} |
||
136 | */ |
||
137 | public function fetchAllAssociative() : array |
||
138 | { |
||
139 | return $this->fetchAll(PDO::FETCH_ASSOC); |
||
140 | } |
||
141 | |||
142 | /** |
||
143 | 1815 | * {@inheritdoc} |
|
144 | */ |
||
145 | public function fetchAllColumn() : array |
||
146 | 1815 | { |
|
147 | 1589 | return $this->fetchAll(PDO::FETCH_COLUMN); |
|
148 | } |
||
149 | 437 | ||
150 | 1815 | /** |
|
151 | * @return Traversable<int,array<int,mixed>> |
||
152 | * |
||
153 | * @throws DriverException |
||
154 | */ |
||
155 | public function iterateNumeric() : Traversable |
||
156 | { |
||
157 | 1815 | return $this->iterate(PDO::FETCH_NUM); |
|
158 | } |
||
159 | 1815 | ||
160 | /** |
||
161 | * @return Traversable<int,array<string,mixed>> |
||
162 | * |
||
163 | * @throws DriverException |
||
164 | */ |
||
165 | 2674 | public function iterateAssociative() : Traversable |
|
166 | { |
||
167 | return $this->iterate(PDO::FETCH_ASSOC); |
||
168 | 2674 | } |
|
169 | |||
170 | /** |
||
171 | * @return Traversable<int,mixed> |
||
172 | * |
||
173 | * @throws DriverException |
||
174 | */ |
||
175 | public function iterateColumn() : Traversable |
||
176 | { |
||
177 | return $this->iterate(PDO::FETCH_COLUMN); |
||
178 | } |
||
179 | 2028 | ||
180 | /** |
||
181 | 2028 | * @return mixed|false |
|
182 | * |
||
183 | * @throws PDOException |
||
184 | */ |
||
185 | 2028 | private function fetch(int $mode) |
|
186 | { |
||
187 | try { |
||
188 | return $this->stmt->fetch($mode); |
||
189 | } catch (\PDOException $exception) { |
||
190 | throw new PDOException($exception); |
||
191 | } |
||
192 | } |
||
193 | 4384 | ||
194 | /** |
||
195 | 4384 | * @return array<int,mixed> |
|
196 | * |
||
197 | * @throws PDOException |
||
198 | */ |
||
199 | 4384 | private function fetchAll(int $mode) : array |
|
200 | { |
||
201 | try { |
||
202 | $data = $this->stmt->fetchAll($mode); |
||
203 | } catch (\PDOException $exception) { |
||
204 | throw new PDOException($exception); |
||
205 | 13 | } |
|
206 | |||
207 | 13 | assert(is_array($data)); |
|
208 | 13 | ||
209 | return $data; |
||
210 | } |
||
211 | |||
212 | /** |
||
213 | * @return Traversable<int,mixed> |
||
214 | * |
||
215 | * @throws PDOException |
||
216 | */ |
||
217 | private function iterate(int $mode) : Traversable |
||
218 | { |
||
219 | $this->stmt->setFetchMode($mode); |
||
220 | |||
221 | try { |
||
222 | yield from $this->stmt; |
||
223 | } catch (\PDOException $exception) { |
||
0 ignored issues
–
show
|
|||
224 | throw new PDOException($exception); |
||
225 | } |
||
226 | } |
||
227 | |||
228 | /** |
||
229 | * Converts DBAL parameter type to PDO parameter type |
||
230 | * |
||
231 | * @param int $type Parameter type |
||
232 | */ |
||
233 | private function convertParamType(int $type) : int |
||
234 | { |
||
235 | if (! isset(self::PARAM_TYPE_MAP[$type])) { |
||
236 | throw UnknownParamType::new($type); |
||
237 | } |
||
238 | |||
239 | return self::PARAM_TYPE_MAP[$type]; |
||
240 | } |
||
241 | } |
||
242 |
This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.
Unreachable code is most often the result of
return
,die
orexit
statements that have been added for debug purposes.In the above example, the last
return false
will never be executed, because a return statement has already been met in every possible execution path.