diff --git a/library/think/Db.php b/library/think/Db.php index ea0071a8..0f69979b 100644 --- a/library/think/Db.php +++ b/library/think/Db.php @@ -49,19 +49,26 @@ use think\db\Query; */ class Db { - // 数据库连接实例 + /** + * @var Connection[] 数据库连接实例 + */ private static $instance = []; - // 查询次数 + + /** + * @var int 查询次数 + */ public static $queryTimes = 0; - // 执行次数 + + /** + * @var int 执行次数 + */ public static $executeTimes = 0; /** - * 数据库初始化 并取得数据库类实例 - * @static + * 数据库初始化,并取得数据库类实例 * @access public - * @param mixed $config 连接配置 - * @param bool|string $name 连接标识 true 强制重新连接 + * @param mixed $config 连接配置 + * @param bool|string $name 连接标识 true 强制重新连接 * @return Connection * @throws Exception */ @@ -70,34 +77,48 @@ class Db if (false === $name) { $name = md5(serialize($config)); } + if (true === $name || !isset(self::$instance[$name])) { // 解析连接参数 支持数组和字符串 $options = self::parseConfig($config); + if (empty($options['type'])) { throw new \InvalidArgumentException('Undefined db type'); } - $class = false !== strpos($options['type'], '\\') ? $options['type'] : '\\think\\db\\connector\\' . ucwords($options['type']); + + $class = false !== strpos($options['type'], '\\') ? + $options['type'] : + '\\think\\db\\connector\\' . ucwords($options['type']); + // 记录初始化信息 if (App::$debug) { Log::record('[ DB ] INIT ' . $options['type'], 'info'); } + if (true === $name) { $name = md5(serialize($config)); } + self::$instance[$name] = new $class($options); } + return self::$instance[$name]; } - - public static function clear() { - self::$instance = null; + + /** + * 清除连接实例 + * @access public + * @return void + */ + public static function clear() + { + self::$instance = []; } /** * 数据库连接参数解析 - * @static * @access private - * @param mixed $config + * @param mixed $config 连接参数 * @return array */ private static function parseConfig($config) @@ -105,30 +126,27 @@ class Db if (empty($config)) { $config = Config::get('database'); } elseif (is_string($config) && false === strpos($config, '/')) { - // 支持读取配置参数 - $config = Config::get($config); - } - if (is_string($config)) { - return self::parseDsn($config); - } else { - return $config; + $config = Config::get($config); // 支持读取配置参数 } + + return is_string($config) ? self::parseDsn($config) : $config; } /** - * DSN解析 + * DSN 解析 * 格式: mysql://username:passwd@localhost:3306/DbName?param1=val1¶m2=val2#utf8 - * @static * @access private - * @param string $dsnStr + * @param string $dsnStr 数据库 DSN 字符串解析 * @return array */ private static function parseDsn($dsnStr) { $info = parse_url($dsnStr); + if (!$info) { return []; } + $dsn = [ 'type' => $info['scheme'], 'username' => isset($info['user']) ? $info['user'] : '', @@ -144,13 +162,19 @@ class Db } else { $dsn['params'] = []; } + return $dsn; } - // 调用驱动类的方法 + /** + * 调用驱动类的方法 + * @access public + * @param string $method 方法名 + * @param array $params 参数 + * @return mixed + */ public static function __callStatic($method, $params) { - // 自动初始化数据库 return call_user_func_array([self::connect(), $method], $params); } } diff --git a/library/think/Debug.php b/library/think/Debug.php index 9994e20c..d3d24429 100644 --- a/library/think/Debug.php +++ b/library/think/Debug.php @@ -16,21 +16,27 @@ use think\response\Redirect; class Debug { - // 区间时间信息 + /** + * @var array 区间时间信息 + */ protected static $info = []; - // 区间内存信息 + + /** + * @var array 区间内存信息 + */ protected static $mem = []; /** * 记录时间(微秒)和内存使用情况 - * @param string $name 标记位置 - * @param mixed $value 标记值 留空则取当前 time 表示仅记录时间 否则同时记录时间和内存 - * @return mixed + * @access public + * @param string $name 标记位置 + * @param mixed $value 标记值(留空则取当前 time 表示仅记录时间 否则同时记录时间和内存) + * @return void */ public static function remark($name, $value = '') { - // 记录时间和内存使用 self::$info[$name] = is_float($value) ? $value : microtime(true); + if ('time' != $value) { self::$mem['mem'][$name] = is_float($value) ? $value : memory_get_usage(); self::$mem['peak'][$name] = memory_get_peak_usage(); @@ -39,23 +45,26 @@ class Debug /** * 统计某个区间的时间(微秒)使用情况 返回值以秒为单位 - * @param string $start 开始标签 - * @param string $end 结束标签 - * @param integer|string $dec 小数位 - * @return integer + * @access public + * @param string $start 开始标签 + * @param string $end 结束标签 + * @param integer $dec 小数位 + * @return string */ public static function getRangeTime($start, $end, $dec = 6) { if (!isset(self::$info[$end])) { self::$info[$end] = microtime(true); } + return number_format((self::$info[$end] - self::$info[$start]), $dec); } /** * 统计从开始到统计时的时间(微秒)使用情况 返回值以秒为单位 - * @param integer|string $dec 小数位 - * @return integer + * @access public + * @param integer $dec 小数位 + * @return string */ public static function getUseTime($dec = 6) { @@ -64,6 +73,7 @@ class Debug /** * 获取当前访问的吞吐率情况 + * @access public * @return string */ public static function getThroughputRate() @@ -73,9 +83,10 @@ class Debug /** * 记录区间的内存使用情况 - * @param string $start 开始标签 - * @param string $end 结束标签 - * @param integer|string $dec 小数位 + * @access public + * @param string $start 开始标签 + * @param string $end 结束标签 + * @param integer $dec 小数位 * @return string */ public static function getRangeMem($start, $end, $dec = 2) @@ -83,19 +94,23 @@ class Debug if (!isset(self::$mem['mem'][$end])) { self::$mem['mem'][$end] = memory_get_usage(); } + $size = self::$mem['mem'][$end] - self::$mem['mem'][$start]; $a = ['B', 'KB', 'MB', 'GB', 'TB']; $pos = 0; + while ($size >= 1024) { $size /= 1024; $pos++; } + return round($size, $dec) . " " . $a[$pos]; } /** * 统计从开始到统计时的内存使用情况 - * @param integer|string $dec 小数位 + * @access public + * @param integer $dec 小数位 * @return string */ public static function getUseMem($dec = 2) @@ -103,103 +118,128 @@ class Debug $size = memory_get_usage() - THINK_START_MEM; $a = ['B', 'KB', 'MB', 'GB', 'TB']; $pos = 0; + while ($size >= 1024) { $size /= 1024; $pos++; } + return round($size, $dec) . " " . $a[$pos]; } /** * 统计区间的内存峰值情况 - * @param string $start 开始标签 - * @param string $end 结束标签 - * @param integer|string $dec 小数位 - * @return mixed + * @access public + * @param string $start 开始标签 + * @param string $end 结束标签 + * @param integer $dec 小数位 + * @return string */ public static function getMemPeak($start, $end, $dec = 2) { if (!isset(self::$mem['peak'][$end])) { self::$mem['peak'][$end] = memory_get_peak_usage(); } + $size = self::$mem['peak'][$end] - self::$mem['peak'][$start]; $a = ['B', 'KB', 'MB', 'GB', 'TB']; $pos = 0; + while ($size >= 1024) { $size /= 1024; $pos++; } + return round($size, $dec) . " " . $a[$pos]; } /** * 获取文件加载信息 - * @param bool $detail 是否显示详细 + * @access public + * @param bool $detail 是否显示详细 * @return integer|array */ public static function getFile($detail = false) { + $files = get_included_files(); + if ($detail) { - $files = get_included_files(); - $info = []; - foreach ($files as $key => $file) { + $info = []; + + foreach ($files as $file) { $info[] = $file . ' ( ' . number_format(filesize($file) / 1024, 2) . ' KB )'; } + return $info; } - return count(get_included_files()); + + return count($files); } /** * 浏览器友好的变量输出 - * @param mixed $var 变量 - * @param boolean $echo 是否输出 默认为true 如果为false 则返回输出字符串 - * @param string $label 标签 默认为空 - * @param integer $flags htmlspecialchars flags - * @return void|string + * @access public + * @param mixed $var 变量 + * @param boolean $echo 是否输出(默认为 true,为 false 则返回输出字符串) + * @param string|null $label 标签(默认为空) + * @param integer $flags htmlspecialchars 的标志 + * @return null|string */ public static function dump($var, $echo = true, $label = null, $flags = ENT_SUBSTITUTE) { $label = (null === $label) ? '' : rtrim($label) . ':'; + ob_start(); var_dump($var); - $output = ob_get_clean(); - $output = preg_replace('/\]\=\>\n(\s+)/m', '] => ', $output); + $output = preg_replace('/\]\=\>\n(\s+)/m', '] => ', ob_get_clean()); + if (IS_CLI) { $output = PHP_EOL . $label . $output . PHP_EOL; } else { if (!extension_loaded('xdebug')) { $output = htmlspecialchars($output, $flags); } + $output = '
' . $label . $output . ''; } + if ($echo) { echo($output); return; - } else { - return $output; } + + return $output; } + /** + * 调试信息注入到响应中 + * @access public + * @param Response $response 响应实例 + * @param string $content 返回的字符串 + * @return void + */ public static function inject(Response $response, &$content) { - $config = Config::get('trace'); - $type = isset($config['type']) ? $config['type'] : 'Html'; - $request = Request::instance(); - $class = false !== strpos($type, '\\') ? $type : '\\think\\debug\\' . ucwords($type); + $config = Config::get('trace'); + $type = isset($config['type']) ? $config['type'] : 'Html'; + $class = false !== strpos($type, '\\') ? $type : '\\think\\debug\\' . ucwords($type); + unset($config['type']); - if (class_exists($class)) { - $trace = new $class($config); - } else { + + if (!class_exists($class)) { throw new ClassNotFoundException('class not exists:' . $class, $class); } + /** @var \think\debug\Console|\think\debug\Html $trace */ + $trace = new $class($config); + if ($response instanceof Redirect) { - //TODO 记录 + // TODO 记录 } else { $output = $trace->output($response, Log::getLog()); + if (is_string($output)) { - // trace调试信息注入 + // trace 调试信息注入 $pos = strripos($content, '