Skip to content

Commit 33426fa

Browse files
committed
Add an iterator method.
1 parent 2679915 commit 33426fa

File tree

1 file changed

+199
-46
lines changed

1 file changed

+199
-46
lines changed

src/PDO.class.php

Lines changed: 199 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -11,41 +11,66 @@
1111
*
1212
* A PHP MySQL PDO class similar to the the Python MySQLdb.
1313
*/
14-
require(dirname(__FILE__) . "/PDO.Log.class.php");
14+
require(__DIR__ . '/PDO.Log.class.php');
15+
require(__DIR__ . '/PDO.Iterator.class.php');
16+
/** Class DB
17+
* @property PDO pdo PDO object
18+
* @property PDOStatement sQuery PDOStatement
19+
* @property PDOLog PDOLog logObject
20+
*/
1521
class DB
1622
{
1723
private $Host;
24+
private $DBPort;
1825
private $DBName;
1926
private $DBUser;
2027
private $DBPassword;
21-
private $DBPort;
2228
private $pdo;
2329
private $sQuery;
24-
private $bConnected = false;
25-
private $log;
30+
private $connectionStatus = false;
31+
private $logObject;
2632
private $parameters;
2733
public $rowCount = 0;
2834
public $columnCount = 0;
2935
public $querycount = 0;
30-
31-
32-
public function __construct($Host, $DBName, $DBUser, $DBPassword, $DBPort = 3306)
36+
37+
38+
private $retryAttempt = 0; // 失败重试次数
39+
const AUTO_RECONNECT = true;
40+
const RETRY_ATTEMPTS = 3; // 最大失败重试次数
41+
42+
/**
43+
* DB constructor.
44+
* @param $Host
45+
* @param $DBPort
46+
* @param $DBName
47+
* @param $DBUser
48+
* @param $DBPassword
49+
*/
50+
public function __construct($Host, $DBPort, $DBName, $DBUser, $DBPassword)
3351
{
34-
$this->log = new Log();
52+
$this->logObject = new PDOLog();
3553
$this->Host = $Host;
54+
$this->DBPort = $DBPort;
3655
$this->DBName = $DBName;
3756
$this->DBUser = $DBUser;
3857
$this->DBPassword = $DBPassword;
39-
$this->DBPort = $DBPort;
40-
$this->Connect();
4158
$this->parameters = array();
59+
$this->Connect();
4260
}
4361

4462

4563
private function Connect()
4664
{
4765
try {
48-
$this->pdo = new PDO('mysql:dbname=' . $this->DBName . ';host=' . $this->Host . ';port=' . $this->DBPort . ';charset=utf8',
66+
$dsn = 'mysql:';
67+
$dsn .= 'host=' . $this->Host . ';';
68+
$dsn .= 'port=' . $this->DBPort . ';';
69+
if (!empty($this->DBName)) {
70+
$dsn .= 'dbname=' . $this->DBName . ';';
71+
}
72+
$dsn .= 'charset=utf8;';
73+
$this->pdo = new PDO($dsn,
4974
$this->DBUser,
5075
$this->DBPassword,
5176
array(
@@ -68,30 +93,36 @@ private function Connect()
6893
//$this->pdo->setAttribute(PDO::ATTR_PERSISTENT, true);//长连接
6994
$this->pdo->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, true);
7095
*/
71-
$this->bConnected = true;
96+
$this->connectionStatus = true;
7297

7398
}
7499
catch (PDOException $e) {
75-
echo $this->ExceptionLog($e->getMessage());
76-
die();
100+
$this->ExceptionLog($e, '', 'Connect');
77101
}
78102
}
79-
80-
81-
public function CloseConnection()
103+
104+
private function SetFailureFlag()
82105
{
83106
$this->pdo = null;
107+
$this->connectionStatus = false;
84108
}
85-
86-
87-
private function Init($query, $parameters = "")
109+
110+
/**
111+
* close pdo connection
112+
*/
113+
public function closeConnection()
114+
{
115+
$this->pdo = null;
116+
}
117+
118+
private function Init($query, $parameters = null, $driverOptions = array())
88119
{
89-
if (!$this->bConnected) {
120+
if (!$this->connectionStatus) {
90121
$this->Connect();
91122
}
92123
try {
93124
$this->parameters = $parameters;
94-
$this->sQuery = $this->pdo->prepare($this->BuildParams($query, $this->parameters));
125+
$this->sQuery = $this->pdo->prepare($this->BuildParams($query, $this->parameters), $driverOptions);
95126

96127
if (!empty($this->parameters)) {
97128
if (array_key_exists(0, $parameters)) {
@@ -105,19 +136,22 @@ private function Init($query, $parameters = "")
105136
$this->sQuery->bindParam($parametersType ? intval($column) : ":" . $column, $this->parameters[$column]); //It would be query after loop end(before 'sQuery->execute()').It is wrong to use $value.
106137
}
107138
}
108-
109-
$this->succes = $this->sQuery->execute();
139+
140+
if (!isset($driverOptions[PDO::ATTR_CURSOR])) {
141+
$this->sQuery->execute();
142+
}
110143
$this->querycount++;
111144
}
112145
catch (PDOException $e) {
113-
echo $this->ExceptionLog($e->getMessage(), $this->BuildParams($query));
114-
die();
146+
$this->ExceptionLog($e, $this->BuildParams($query), 'Init', array('query' => $query, 'parameters' => $parameters));
147+
115148
}
116149

117150
$this->parameters = array();
118151
}
119152

120-
private function BuildParams($query, $params = array()){
153+
private function BuildParams($query, $params = null)
154+
{
121155
if (!empty($params)) {
122156
$array_parameter_found = false;
123157
foreach ($params as $parameter_key => $parameter) {
@@ -143,30 +177,116 @@ private function BuildParams($query, $params = array()){
143177
}
144178
return $query;
145179
}
146-
147-
148-
public function query($query, $params = null, $fetchmode = PDO::FETCH_ASSOC)
180+
181+
/**
182+
* @return bool
183+
*/
184+
public function beginTransaction()
185+
{
186+
return $this->pdo->beginTransaction();
187+
}
188+
189+
/**
190+
* @return bool
191+
*/
192+
public function commit()
193+
{
194+
return $this->pdo->commit();
195+
}
196+
197+
/**
198+
* @return bool
199+
*/
200+
public function rollBack()
201+
{
202+
return $this->pdo->rollBack();
203+
}
204+
205+
/**
206+
* @return bool
207+
*/
208+
public function inTransaction()
209+
{
210+
return $this->pdo->inTransaction();
211+
}
212+
213+
/**
214+
* execute a sql query, returns an result array in the select operation, and returns the number of rows affected in other operations
215+
* @param string $query
216+
* @param null $params
217+
* @param int $fetchMode
218+
* @return array|int|null
219+
*/
220+
public function query($query, $params = null, $fetchMode = PDO::FETCH_ASSOC)
149221
{
150222
$query = trim($query);
151223
$rawStatement = explode(" ", $query);
152224
$this->Init($query, $params);
153225
$statement = strtolower($rawStatement[0]);
154226
if ($statement === 'select' || $statement === 'show') {
155-
return $this->sQuery->fetchAll($fetchmode);
227+
return $this->sQuery->fetchAll($fetchMode);
156228
} elseif ($statement === 'insert' || $statement === 'update' || $statement === 'delete') {
157229
return $this->sQuery->rowCount();
158230
} else {
159231
return NULL;
160232
}
161233
}
162-
163-
234+
235+
/**
236+
* execute a sql query, returns an iterator in the select operation, and returns the number of rows affected in other operations
237+
* @param string $query
238+
* @param null $params
239+
* @param int $fetchMode
240+
* @return int|null|PDOIterator
241+
*/
242+
public function iterator($query, $params = null, $fetchMode = PDO::FETCH_ASSOC)
243+
{
244+
$query = trim($query);
245+
$rawStatement = explode(" ", $query);
246+
$this->Init($query, $params, array(PDO::ATTR_CURSOR => PDO::CURSOR_SCROLL));
247+
$statement = strtolower($rawStatement[0]);
248+
if ($statement === 'select' || $statement === 'show') {
249+
return new PDOIterator($this->sQuery, $fetchMode);
250+
} elseif ($statement === 'insert' || $statement === 'update' || $statement === 'delete') {
251+
return $this->sQuery->rowCount();
252+
} else {
253+
return NULL;
254+
}
255+
}
256+
257+
/**
258+
* @param $tableName
259+
* @param null $params
260+
* @return bool|string
261+
*/
262+
public function insert($tableName, $params = null)
263+
{
264+
$keys = array_keys($params);
265+
$rowCount = $this->query(
266+
'INSERT INTO `' . $tableName . '` (`' . implode('`,`', $keys) . '`)
267+
VALUES (:' . implode(',:', $keys) . ')',
268+
$params
269+
);
270+
if ($rowCount === 0) {
271+
return false;
272+
}
273+
return $this->lastInsertId();
274+
}
275+
276+
/**
277+
* @return string
278+
*/
164279
public function lastInsertId()
165280
{
166281
return $this->pdo->lastInsertId();
167282
}
168-
169-
283+
284+
285+
/**
286+
* @param $query
287+
* @param null $params
288+
* @return array
289+
*/
170290
public function column($query, $params = null)
171291
{
172292
$this->Init($query, $params);
@@ -177,7 +297,12 @@ public function column($query, $params = null)
177297
return $resultColumn;
178298
}
179299

180-
300+
/**
301+
* @param $query
302+
* @param null $params
303+
* @param int $fetchmode
304+
* @return mixed
305+
*/
181306
public function row($query, $params = null, $fetchmode = PDO::FETCH_ASSOC)
182307
{
183308
$this->Init($query, $params);
@@ -187,28 +312,56 @@ public function row($query, $params = null, $fetchmode = PDO::FETCH_ASSOC)
187312
$this->sQuery->closeCursor();
188313
return $resultRow;
189314
}
190-
191-
315+
316+
/**
317+
* @param $query
318+
* @param null $params
319+
* @return mixed
320+
*/
192321
public function single($query, $params = null)
193322
{
194323
$this->Init($query, $params);
195324
return $this->sQuery->fetchColumn();
196325
}
197-
198-
199-
private function ExceptionLog($message, $sql = "")
326+
327+
/**
328+
* @param PDOException $e
329+
* @param string $sql
330+
* @param string $method
331+
* @param array $parameters
332+
*/
333+
private function ExceptionLog(PDOException $e, $sql = "", $method = '', $parameters = array())
200334
{
335+
$message = $e->getMessage();
201336
$exception = 'Unhandled Exception. <br />';
202337
$exception .= $message;
203338
$exception .= "<br /> You can find the error back in the log.";
204339

205340
if (!empty($sql)) {
206341
$message .= "\r\nRaw SQL : " . $sql;
207342
}
208-
$this->log->write($message, $this->DBName . md5($this->DBPassword));
209-
//Prevent search engines to crawl
210-
header("HTTP/1.1 500 Internal Server Error");
211-
header("Status: 500 Internal Server Error");
212-
return $exception;
343+
$this->logObject->write($message, $this->DBName . md5($this->DBPassword));
344+
if (
345+
self::AUTO_RECONNECT
346+
&& $this->retryAttempt < self::RETRY_ATTEMPTS
347+
&& stripos($message, 'server has gone away') !== false
348+
&& !empty($method)
349+
&& !$this->inTransaction()
350+
) {
351+
$this->SetFailureFlag();
352+
$this->retryAttempt ++;
353+
$this->logObject->write('Retry ' . $this->retryAttempt . ' times', $this->DBName . md5($this->DBPassword));
354+
call_user_func_array(array($this, $method), $parameters);
355+
} else {
356+
if (($this->pdo === null || !$this->inTransaction()) && php_sapi_name() !== "cli") {
357+
//Prevent search engines to crawl
358+
header("HTTP/1.1 500 Internal Server Error");
359+
header("Status: 500 Internal Server Error");
360+
echo $exception;
361+
exit();
362+
} else {
363+
throw $e;
364+
}
365+
}
213366
}
214367
}

0 commit comments

Comments
 (0)