Changeset 823
- Timestamp:
- Feb 25, 2015, 9:19:59 AM (10 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
aowow/includes/DbSimple/Generic.php
r822 r823 165 165 166 166 /** 167 * Support for error tracking. 168 * Can hold error messages, error queries and build proper stacktraces. 169 */ 170 class DbSimple_Generic_LastError 171 { 172 var $error = null; 173 var $errmsg = null; 174 var $errorHandler = null; 175 var $ignoresInTraceRe = 'DbSimple_.*::.* | call_user_func.*'; 176 177 /** 178 * abstract void _logQuery($query) 179 * Must be overriden in derived class. 180 */ 181 function _logQuery($query) 182 { 183 die("Method must be defined in derived class. Abstract function called at ".__FILE__." line ".__LINE__);; 184 } 185 186 /** 187 * void _resetLastError() 188 * Reset the last error. Must be called on correct queries. 189 */ 190 function _resetLastError() 191 { 192 $this->error = $this->errmsg = null; 193 } 194 195 /** 196 * void _setLastError(int $code, string $message, string $query) 197 * Fill $this->error property with error information. Error context 198 * (code initiated the query outside DbSimple) is assigned automatically. 199 */ 200 function _setLastError($code, $msg, $query) 201 { 202 $context = "unknown"; 203 if ($t = $this->findLibraryCaller()) { 204 $context = (isset($t['file'])? $t['file'] : '?') . ' line ' . (isset($t['line'])? $t['line'] : '?'); 205 } 206 $this->error = array( 207 'code' => $code, 208 'message' => rtrim($msg), 209 'query' => $query, 210 'context' => $context, 211 ); 212 $this->errmsg = rtrim($msg) . ($context? " at $context" : ""); 213 214 $this->_logQuery(" -- error #".$code.": ".preg_replace('/(\r?\n)+/s', ' ', $this->errmsg)); 215 216 if (is_callable($this->errorHandler)) { 217 call_user_func($this->errorHandler, $this->errmsg, $this->error); 218 } 219 220 return null; 221 } 222 223 224 /** 225 * callback setErrorHandler(callback $handler) 226 * Set new error handler called on database errors. 227 * Handler gets 3 arguments: 228 * - error message 229 * - full error context information (last query etc.) 230 */ 231 function setErrorHandler($handler) 232 { 233 $prev = $this->errorHandler; 234 $this->errorHandler = $handler; 235 // In case of setting first error handler for already existed 236 // error - call the handler now (usual after connect()). 237 if (!$prev && $this->error) { 238 call_user_func($this->errorHandler, $this->errmsg, $this->error); 239 } 240 return $prev; 241 } 242 243 /** 244 * void addIgnoreInTrace($reName) 245 * Add regular expression matching ClassName::functionName or functionName. 246 * Matched stack frames will be ignored in stack traces passed to query logger. 247 */ 248 function addIgnoreInTrace($name) 249 { 250 $this->ignoresInTraceRe .= "|" . $name; 251 } 252 253 /** 254 * array of array findLibraryCaller() 255 * Return part of stacktrace before calling first library method. 256 * Used in debug purposes (query logging etc.). 257 */ 258 function findLibraryCaller() 259 { 260 $caller = call_user_func( 261 array(&$this, 'debug_backtrace_smart'), 262 $this->ignoresInTraceRe, 263 true 264 ); 265 return $caller; 266 } 267 268 /** 269 * array debug_backtrace_smart($ignoresRe=null, $returnCaller=false) 270 * 271 * Return stacktrace. Correctly work with call_user_func* 272 * (totally skip them correcting caller references). 273 * If $returnCaller is true, return only first matched caller, 274 * not all stacktrace. 275 * 276 * @version 2.03 277 */ 278 function debug_backtrace_smart($ignoresRe=null, $returnCaller=false) 279 { 280 if (!is_callable($tracer='debug_backtrace')) return array(); 281 $trace = $tracer(); 282 283 if ($ignoresRe !== null) $ignoresRe = "/^(?>{$ignoresRe})$/six"; 284 $smart = array(); 285 $framesSeen = 0; 286 for ($i=0, $n=count($trace); $i<$n; $i++) { 287 $t = $trace[$i]; 288 if (!$t) continue; 289 290 // Next frame. 291 $next = isset($trace[$i+1])? $trace[$i+1] : null; 292 293 // Dummy frame before call_user_func* frames. 294 if (!isset($t['file'])) { 295 $t['over_function'] = $trace[$i+1]['function']; 296 $t = $t + $trace[$i+1]; 297 $trace[$i+1] = null; // skip call_user_func on next iteration 298 } 299 300 // Skip myself frame. 301 if (++$framesSeen < 2) continue; 302 303 // 'class' and 'function' field of next frame define where 304 // this frame function situated. Skip frames for functions 305 // situated in ignored places. 306 if ($ignoresRe && $next) { 307 // Name of function "inside which" frame was generated. 308 $frameCaller = (isset($next['class'])? $next['class'].'::' : '') . (isset($next['function'])? $next['function'] : ''); 309 if (preg_match($ignoresRe, $frameCaller)) continue; 310 } 311 312 // On each iteration we consider ability to add PREVIOUS frame 313 // to $smart stack. 314 if ($returnCaller) return $t; 315 $smart[] = $t; 316 } 317 return $smart; 318 } 319 320 } 321 322 /** 167 323 * Base class for all databases. 168 324 * Can create transactions and new BLOBs, parse DSNs. … … 1203 1359 1204 1360 1205 /**1206 * Support for error tracking.1207 * Can hold error messages, error queries and build proper stacktraces.1208 */1209 class DbSimple_Generic_LastError1210 {1211 var $error = null;1212 var $errmsg = null;1213 var $errorHandler = null;1214 var $ignoresInTraceRe = 'DbSimple_.*::.* | call_user_func.*';1215 1216 /**1217 * abstract void _logQuery($query)1218 * Must be overriden in derived class.1219 */1220 function _logQuery($query)1221 {1222 die("Method must be defined in derived class. Abstract function called at ".__FILE__." line ".__LINE__);;1223 }1224 1225 /**1226 * void _resetLastError()1227 * Reset the last error. Must be called on correct queries.1228 */1229 function _resetLastError()1230 {1231 $this->error = $this->errmsg = null;1232 }1233 1234 /**1235 * void _setLastError(int $code, string $message, string $query)1236 * Fill $this->error property with error information. Error context1237 * (code initiated the query outside DbSimple) is assigned automatically.1238 */1239 function _setLastError($code, $msg, $query)1240 {1241 $context = "unknown";1242 if ($t = $this->findLibraryCaller()) {1243 $context = (isset($t['file'])? $t['file'] : '?') . ' line ' . (isset($t['line'])? $t['line'] : '?');1244 }1245 $this->error = array(1246 'code' => $code,1247 'message' => rtrim($msg),1248 'query' => $query,1249 'context' => $context,1250 );1251 $this->errmsg = rtrim($msg) . ($context? " at $context" : "");1252 1253 $this->_logQuery(" -- error #".$code.": ".preg_replace('/(\r?\n)+/s', ' ', $this->errmsg));1254 1255 if (is_callable($this->errorHandler)) {1256 call_user_func($this->errorHandler, $this->errmsg, $this->error);1257 }1258 1259 return null;1260 }1261 1262 1263 /**1264 * callback setErrorHandler(callback $handler)1265 * Set new error handler called on database errors.1266 * Handler gets 3 arguments:1267 * - error message1268 * - full error context information (last query etc.)1269 */1270 function setErrorHandler($handler)1271 {1272 $prev = $this->errorHandler;1273 $this->errorHandler = $handler;1274 // In case of setting first error handler for already existed1275 // error - call the handler now (usual after connect()).1276 if (!$prev && $this->error) {1277 call_user_func($this->errorHandler, $this->errmsg, $this->error);1278 }1279 return $prev;1280 }1281 1282 /**1283 * void addIgnoreInTrace($reName)1284 * Add regular expression matching ClassName::functionName or functionName.1285 * Matched stack frames will be ignored in stack traces passed to query logger.1286 */1287 function addIgnoreInTrace($name)1288 {1289 $this->ignoresInTraceRe .= "|" . $name;1290 }1291 1292 /**1293 * array of array findLibraryCaller()1294 * Return part of stacktrace before calling first library method.1295 * Used in debug purposes (query logging etc.).1296 */1297 function findLibraryCaller()1298 {1299 $caller = call_user_func(1300 array(&$this, 'debug_backtrace_smart'),1301 $this->ignoresInTraceRe,1302 true1303 );1304 return $caller;1305 }1306 1307 /**1308 * array debug_backtrace_smart($ignoresRe=null, $returnCaller=false)1309 *1310 * Return stacktrace. Correctly work with call_user_func*1311 * (totally skip them correcting caller references).1312 * If $returnCaller is true, return only first matched caller,1313 * not all stacktrace.1314 *1315 * @version 2.031316 */1317 function debug_backtrace_smart($ignoresRe=null, $returnCaller=false)1318 {1319 if (!is_callable($tracer='debug_backtrace')) return array();1320 $trace = $tracer();1321 1322 if ($ignoresRe !== null) $ignoresRe = "/^(?>{$ignoresRe})$/six";1323 $smart = array();1324 $framesSeen = 0;1325 for ($i=0, $n=count($trace); $i<$n; $i++) {1326 $t = $trace[$i];1327 if (!$t) continue;1328 1329 // Next frame.1330 $next = isset($trace[$i+1])? $trace[$i+1] : null;1331 1332 // Dummy frame before call_user_func* frames.1333 if (!isset($t['file'])) {1334 $t['over_function'] = $trace[$i+1]['function'];1335 $t = $t + $trace[$i+1];1336 $trace[$i+1] = null; // skip call_user_func on next iteration1337 }1338 1339 // Skip myself frame.1340 if (++$framesSeen < 2) continue;1341 1342 // 'class' and 'function' field of next frame define where1343 // this frame function situated. Skip frames for functions1344 // situated in ignored places.1345 if ($ignoresRe && $next) {1346 // Name of function "inside which" frame was generated.1347 $frameCaller = (isset($next['class'])? $next['class'].'::' : '') . (isset($next['function'])? $next['function'] : '');1348 if (preg_match($ignoresRe, $frameCaller)) continue;1349 }1350 1351 // On each iteration we consider ability to add PREVIOUS frame1352 // to $smart stack.1353 if ($returnCaller) return $t;1354 $smart[] = $t;1355 }1356 return $smart;1357 }1358 1359 }
Note:
See TracChangeset
for help on using the changeset viewer.