1<?php 2 3namespace Doctrine\DBAL\Driver; 4 5use Doctrine\DBAL\FetchMode; 6use Doctrine\DBAL\ParameterType; 7use PDO; 8use const E_USER_DEPRECATED; 9use function array_slice; 10use function assert; 11use function func_get_args; 12use function is_array; 13use function sprintf; 14use function trigger_error; 15 16/** 17 * The PDO implementation of the Statement interface. 18 * Used by all PDO-based drivers. 19 */ 20class PDOStatement extends \PDOStatement implements Statement 21{ 22 private const PARAM_TYPE_MAP = [ 23 ParameterType::NULL => PDO::PARAM_NULL, 24 ParameterType::INTEGER => PDO::PARAM_INT, 25 ParameterType::STRING => PDO::PARAM_STR, 26 ParameterType::BINARY => PDO::PARAM_LOB, 27 ParameterType::LARGE_OBJECT => PDO::PARAM_LOB, 28 ParameterType::BOOLEAN => PDO::PARAM_BOOL, 29 ]; 30 31 private const FETCH_MODE_MAP = [ 32 FetchMode::ASSOCIATIVE => PDO::FETCH_ASSOC, 33 FetchMode::NUMERIC => PDO::FETCH_NUM, 34 FetchMode::MIXED => PDO::FETCH_BOTH, 35 FetchMode::STANDARD_OBJECT => PDO::FETCH_OBJ, 36 FetchMode::COLUMN => PDO::FETCH_COLUMN, 37 FetchMode::CUSTOM_OBJECT => PDO::FETCH_CLASS, 38 ]; 39 40 /** 41 * Protected constructor. 42 */ 43 protected function __construct() 44 { 45 } 46 47 /** 48 * {@inheritdoc} 49 */ 50 public function setFetchMode($fetchMode, $arg2 = null, $arg3 = null) 51 { 52 $fetchMode = $this->convertFetchMode($fetchMode); 53 54 // This thin wrapper is necessary to shield against the weird signature 55 // of PDOStatement::setFetchMode(): even if the second and third 56 // parameters are optional, PHP will not let us remove it from this 57 // declaration. 58 try { 59 if ($arg2 === null && $arg3 === null) { 60 return parent::setFetchMode($fetchMode); 61 } 62 63 if ($arg3 === null) { 64 return parent::setFetchMode($fetchMode, $arg2); 65 } 66 67 return parent::setFetchMode($fetchMode, $arg2, $arg3); 68 } catch (\PDOException $exception) { 69 throw new PDOException($exception); 70 } 71 } 72 73 /** 74 * {@inheritdoc} 75 */ 76 public function bindValue($param, $value, $type = ParameterType::STRING) 77 { 78 $type = $this->convertParamType($type); 79 80 try { 81 return parent::bindValue($param, $value, $type); 82 } catch (\PDOException $exception) { 83 throw new PDOException($exception); 84 } 85 } 86 87 /** 88 * {@inheritdoc} 89 */ 90 public function bindParam($column, &$variable, $type = ParameterType::STRING, $length = null, $driverOptions = null) 91 { 92 $type = $this->convertParamType($type); 93 94 try { 95 return parent::bindParam($column, $variable, $type, ...array_slice(func_get_args(), 3)); 96 } catch (\PDOException $exception) { 97 throw new PDOException($exception); 98 } 99 } 100 101 /** 102 * {@inheritdoc} 103 */ 104 public function closeCursor() 105 { 106 try { 107 return parent::closeCursor(); 108 } catch (\PDOException $exception) { 109 // Exceptions not allowed by the interface. 110 // In case driver implementations do not adhere to the interface, silence exceptions here. 111 return true; 112 } 113 } 114 115 /** 116 * {@inheritdoc} 117 */ 118 public function execute($params = null) 119 { 120 try { 121 return parent::execute($params); 122 } catch (\PDOException $exception) { 123 throw new PDOException($exception); 124 } 125 } 126 127 /** 128 * {@inheritdoc} 129 */ 130 public function fetch($fetchMode = null, $cursorOrientation = PDO::FETCH_ORI_NEXT, $cursorOffset = 0) 131 { 132 $args = func_get_args(); 133 134 if (isset($args[0])) { 135 $args[0] = $this->convertFetchMode($args[0]); 136 } 137 138 try { 139 return parent::fetch(...$args); 140 } catch (\PDOException $exception) { 141 throw new PDOException($exception); 142 } 143 } 144 145 /** 146 * {@inheritdoc} 147 */ 148 public function fetchAll($fetchMode = null, $fetchArgument = null, $ctorArgs = null) 149 { 150 $args = func_get_args(); 151 152 if (isset($args[0])) { 153 $args[0] = $this->convertFetchMode($args[0]); 154 } 155 156 if ($fetchMode === null && $fetchArgument === null && $ctorArgs === null) { 157 $args = []; 158 } elseif ($fetchArgument === null && $ctorArgs === null) { 159 $args = [$fetchMode]; 160 } elseif ($ctorArgs === null) { 161 $args = [$fetchMode, $fetchArgument]; 162 } else { 163 $args = [$fetchMode, $fetchArgument, $ctorArgs]; 164 } 165 166 try { 167 $data = parent::fetchAll(...$args); 168 assert(is_array($data)); 169 170 return $data; 171 } catch (\PDOException $exception) { 172 throw new PDOException($exception); 173 } 174 } 175 176 /** 177 * {@inheritdoc} 178 */ 179 public function fetchColumn($columnIndex = 0) 180 { 181 try { 182 return parent::fetchColumn($columnIndex); 183 } catch (\PDOException $exception) { 184 throw new PDOException($exception); 185 } 186 } 187 188 /** 189 * Converts DBAL parameter type to PDO parameter type 190 * 191 * @param int $type Parameter type 192 */ 193 private function convertParamType(int $type) : int 194 { 195 if (! isset(self::PARAM_TYPE_MAP[$type])) { 196 // TODO: next major: throw an exception 197 @trigger_error(sprintf( 198 'Using a PDO parameter type (%d given) is deprecated and will cause an error in Doctrine 3.0', 199 $type 200 ), E_USER_DEPRECATED); 201 202 return $type; 203 } 204 205 return self::PARAM_TYPE_MAP[$type]; 206 } 207 208 /** 209 * Converts DBAL fetch mode to PDO fetch mode 210 * 211 * @param int $fetchMode Fetch mode 212 */ 213 private function convertFetchMode(int $fetchMode) : int 214 { 215 if (! isset(self::FETCH_MODE_MAP[$fetchMode])) { 216 // TODO: next major: throw an exception 217 @trigger_error(sprintf( 218 'Using a PDO fetch mode or their combination (%d given)' . 219 ' is deprecated and will cause an error in Doctrine 3.0', 220 $fetchMode 221 ), E_USER_DEPRECATED); 222 223 return $fetchMode; 224 } 225 226 return self::FETCH_MODE_MAP[$fetchMode]; 227 } 228} 229