PDOStatement.php 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309
  1. <?php
  2. namespace Doctrine\DBAL\Driver;
  3. use Doctrine\DBAL\Driver\PDO\Exception;
  4. use Doctrine\DBAL\Driver\Statement as StatementInterface;
  5. use Doctrine\DBAL\FetchMode;
  6. use Doctrine\DBAL\ParameterType;
  7. use Doctrine\Deprecations\Deprecation;
  8. use PDO;
  9. use PDOException;
  10. use function array_slice;
  11. use function assert;
  12. use function func_get_args;
  13. use function is_array;
  14. /**
  15. * The PDO implementation of the Statement interface.
  16. * Used by all PDO-based drivers.
  17. *
  18. * @deprecated Use {@link Statement} instead
  19. */
  20. class PDOStatement extends \PDOStatement implements StatementInterface, Result
  21. {
  22. use PDOStatementImplementations;
  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::ASCII => PDO::PARAM_STR,
  28. ParameterType::BINARY => PDO::PARAM_LOB,
  29. ParameterType::LARGE_OBJECT => PDO::PARAM_LOB,
  30. ParameterType::BOOLEAN => PDO::PARAM_BOOL,
  31. ];
  32. private const FETCH_MODE_MAP = [
  33. FetchMode::ASSOCIATIVE => PDO::FETCH_ASSOC,
  34. FetchMode::NUMERIC => PDO::FETCH_NUM,
  35. FetchMode::MIXED => PDO::FETCH_BOTH,
  36. FetchMode::STANDARD_OBJECT => PDO::FETCH_OBJ,
  37. FetchMode::COLUMN => PDO::FETCH_COLUMN,
  38. FetchMode::CUSTOM_OBJECT => PDO::FETCH_CLASS,
  39. ];
  40. /**
  41. * Protected constructor.
  42. *
  43. * @internal The statement can be only instantiated by its driver connection.
  44. */
  45. protected function __construct()
  46. {
  47. }
  48. /**
  49. * {@inheritdoc}
  50. */
  51. public function bindValue($param, $value, $type = ParameterType::STRING)
  52. {
  53. $type = $this->convertParamType($type);
  54. try {
  55. return parent::bindValue($param, $value, $type);
  56. } catch (PDOException $exception) {
  57. throw Exception::new($exception);
  58. }
  59. }
  60. /**
  61. * @param mixed $param
  62. * @param mixed $variable
  63. * @param int $type
  64. * @param int|null $length
  65. * @param mixed $driverOptions
  66. *
  67. * @return bool
  68. */
  69. public function bindParam($param, &$variable, $type = ParameterType::STRING, $length = null, $driverOptions = null)
  70. {
  71. $type = $this->convertParamType($type);
  72. try {
  73. return parent::bindParam($param, $variable, $type, ...array_slice(func_get_args(), 3));
  74. } catch (PDOException $exception) {
  75. throw Exception::new($exception);
  76. }
  77. }
  78. /**
  79. * {@inheritdoc}
  80. *
  81. * @deprecated Use free() instead.
  82. */
  83. public function closeCursor()
  84. {
  85. try {
  86. return parent::closeCursor();
  87. } catch (PDOException $exception) {
  88. // Exceptions not allowed by the interface.
  89. // In case driver implementations do not adhere to the interface, silence exceptions here.
  90. return true;
  91. }
  92. }
  93. /**
  94. * {@inheritdoc}
  95. */
  96. public function execute($params = null)
  97. {
  98. try {
  99. return parent::execute($params);
  100. } catch (PDOException $exception) {
  101. throw Exception::new($exception);
  102. }
  103. }
  104. /**
  105. * {@inheritdoc}
  106. *
  107. * @deprecated Use fetchNumeric(), fetchAssociative() or fetchOne() instead.
  108. */
  109. public function fetch($fetchMode = null, $cursorOrientation = PDO::FETCH_ORI_NEXT, $cursorOffset = 0)
  110. {
  111. $args = func_get_args();
  112. if (isset($args[0])) {
  113. $args[0] = $this->convertFetchMode($args[0]);
  114. }
  115. try {
  116. return parent::fetch(...$args);
  117. } catch (PDOException $exception) {
  118. throw Exception::new($exception);
  119. }
  120. }
  121. /**
  122. * {@inheritdoc}
  123. *
  124. * @deprecated Use fetchOne() instead.
  125. */
  126. public function fetchColumn($columnIndex = 0)
  127. {
  128. try {
  129. return parent::fetchColumn($columnIndex);
  130. } catch (PDOException $exception) {
  131. throw Exception::new($exception);
  132. }
  133. }
  134. /**
  135. * {@inheritdoc}
  136. */
  137. public function fetchNumeric()
  138. {
  139. return $this->fetch(PDO::FETCH_NUM);
  140. }
  141. /**
  142. * {@inheritdoc}
  143. */
  144. public function fetchAssociative()
  145. {
  146. return $this->fetch(PDO::FETCH_ASSOC);
  147. }
  148. /**
  149. * {@inheritdoc}
  150. */
  151. public function fetchOne()
  152. {
  153. return $this->fetch(PDO::FETCH_COLUMN);
  154. }
  155. /**
  156. * {@inheritdoc}
  157. */
  158. public function fetchAllNumeric(): array
  159. {
  160. return $this->fetchAll(PDO::FETCH_NUM);
  161. }
  162. /**
  163. * {@inheritdoc}
  164. */
  165. public function fetchAllAssociative(): array
  166. {
  167. return $this->fetchAll(PDO::FETCH_ASSOC);
  168. }
  169. /**
  170. * {@inheritdoc}
  171. */
  172. public function fetchFirstColumn(): array
  173. {
  174. return $this->fetchAll(PDO::FETCH_COLUMN);
  175. }
  176. public function free(): void
  177. {
  178. parent::closeCursor();
  179. }
  180. /**
  181. * @param mixed ...$args
  182. */
  183. private function doSetFetchMode(int $fetchMode, ...$args): bool
  184. {
  185. $fetchMode = $this->convertFetchMode($fetchMode);
  186. // This thin wrapper is necessary to shield against the weird signature
  187. // of PDOStatement::setFetchMode(): even if the second and third
  188. // parameters are optional, PHP will not let us remove it from this
  189. // declaration.
  190. $slice = [];
  191. foreach ($args as $arg) {
  192. if ($arg === null) {
  193. break;
  194. }
  195. $slice[] = $arg;
  196. }
  197. try {
  198. return parent::setFetchMode($fetchMode, ...$slice);
  199. } catch (PDOException $exception) {
  200. throw Exception::new($exception);
  201. }
  202. }
  203. /**
  204. * @param mixed ...$args
  205. *
  206. * @return mixed[]
  207. */
  208. private function doFetchAll(...$args): array
  209. {
  210. if (isset($args[0])) {
  211. $args[0] = $this->convertFetchMode($args[0]);
  212. }
  213. $slice = [];
  214. foreach ($args as $arg) {
  215. if ($arg === null) {
  216. break;
  217. }
  218. $slice[] = $arg;
  219. }
  220. try {
  221. $data = parent::fetchAll(...$slice);
  222. } catch (PDOException $exception) {
  223. throw Exception::new($exception);
  224. }
  225. assert(is_array($data));
  226. return $data;
  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. // TODO: next major: throw an exception
  237. Deprecation::trigger(
  238. 'doctrine/dbal',
  239. 'https://github.com/doctrine/dbal/pull/3088',
  240. 'Using a PDO parameter type (%d given) is deprecated, ' .
  241. 'use \Doctrine\DBAL\Types\Types constants instead.',
  242. $type
  243. );
  244. return $type;
  245. }
  246. return self::PARAM_TYPE_MAP[$type];
  247. }
  248. /**
  249. * Converts DBAL fetch mode to PDO fetch mode
  250. *
  251. * @param int $fetchMode Fetch mode
  252. */
  253. private function convertFetchMode(int $fetchMode): int
  254. {
  255. if (! isset(self::FETCH_MODE_MAP[$fetchMode])) {
  256. Deprecation::trigger(
  257. 'doctrine/dbal',
  258. 'https://github.com/doctrine/dbal/pull/3088',
  259. 'Using an unsupported PDO fetch mode or a bitmask of fetch modes (%d given)' .
  260. ' is deprecated and will cause an error in Doctrine DBAL 3.0',
  261. $fetchMode
  262. );
  263. return $fetchMode;
  264. }
  265. return self::FETCH_MODE_MAP[$fetchMode];
  266. }
  267. }