Changeset 823


Ignore:
Timestamp:
Feb 25, 2015, 9:19:59 AM (9 years ago)
Author:
chronos
Message:
  • Fixed: PHP SIGSEG because class declaration was after first usage of it.
File:
1 edited

Legend:

Unmodified
Added
Removed
  • aowow/includes/DbSimple/Generic.php

    r822 r823  
    165165
    166166/**
     167 * Support for error tracking.
     168 * Can hold error messages, error queries and build proper stacktraces.
     169 */
     170class 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/**
    167323 * Base class for all databases.
    168324 * Can create transactions and new BLOBs, parse DSNs.
     
    12031359
    12041360
    1205 /**
    1206  * Support for error tracking.
    1207  * Can hold error messages, error queries and build proper stacktraces.
    1208  */
    1209 class DbSimple_Generic_LastError
    1210 {
    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 context
    1237      * (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 message
    1268      * - 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 existed
    1275         // 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             true
    1303         );
    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.03
    1316      */
    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 iteration
    1337             }
    1338            
    1339             // Skip myself frame.
    1340             if (++$framesSeen < 2) continue;
    1341 
    1342             // 'class' and 'function' field of next frame define where
    1343             // this frame function situated. Skip frames for functions
    1344             // 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 frame
    1352             // 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.