deepeloper / pdo-debugging
PDO 调试和基准测试工具
2.3.0
2022-12-10 14:51 UTC
Requires
- php: ^7.4
- ext-json: *
- ext-pdo: *
Requires (Dev)
README
兼容性
安装
运行 composer require deepeloper/pdo-debugging
。
基准测试
允许按PDO连接收集以下基准指标
- 全局
-
- 查询数量/时间;
-
- 预处理数量/时间;
-
- 获取数量/时间;
-
- 提交数量/时间;
-
- 回滚数量/时间;
-
- 调用时间总和
-
-
- PDO::__construct();
-
-
-
- PDO::beginTransaction();
-
-
-
- PDO::commit();
-
-
-
- PDO::exec();
-
-
-
- PDO::prepare();
-
-
-
- PDO::query();
-
-
-
- PDO::rollBack();
-
-
-
- PDOStatement::execute();
-
-
-
- PDOStatement::fetch*();
-
- 语句
-
- 查询数量/时间;
-
- 获取数量/时间;
-
- 调用时间总和
-
-
- PDOStatement::execute();
-
-
-
- PDOStatement::fetch*().
-
基准测试用法
use deepeloper\PDO\PDOExcavated; $pdo = new PDOExcavated( $dsn, $username, $password, [ PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDOExcavated::ATTR_DEBUG => [], ] ); $pdo->beginTransaction(); $stmt = $pdo->query("SELECT 1"); $stmt->fetch(); $pdo->commit(); $pdo->beginTransaction(); $stmt = $pdo->prepare("SELECT ?"); $stmt->bindValue(1, 100500, PDO::PARAM_INT); $stmt->execute(); $stmt->fetch(); $pdo->rollBack(); echo "Global benchmarks: "; print_r($pdo->getBenchmarks()); echo "\nStatement benchmarks: ";print_r($stmt->getBenchmarks()); echo sprintf("\nLast query: %s\n", $stmt->getLastExecutedQuery());
将输出
Global benchmarks: Array
(
[query] => Array
(
[count] => 2
[time] => ...
)
[prepare] => Array
(
[count] => 1
[time] => ...
)
[fetch] => Array
(
[count] => 2
[time] => ...
)
[commit] => Array
(
[count] => 1
[time] => ...
)
[rollBack] => Array
(
[count] => 1
[time] => ...
)
[total] => Array
(
[time] => ...
)
)
Statement benchmarks: Array
(
[query] => Array
(
[count] => 1
[time] => ...
)
[fetch] => Array
(
[count] => 1
[time] => ...
)
[total] => Array
(
[time] => ...
)
)
Last query: SELECT 100500
调试
允许处理以下方法调用
- PDO::__construct();
- PDO::beginTransaction();
- PDO::commit();
- PDO::exec();
- PDO::prepare();
- PDO::query();
- PDO::rollBack();
- PDOStatement::execute().
允许从以下方法记录替换占位符的查询
- PDO::exec();
- PDO::query();
- PDOStatement::execute().
调试用法
use deepeloper\PDO\LoggerInterface; use deepeloper\PDO\PDOExcavated; class Logger implements LoggerInterface { /** * Logs message. * * @param string $message * @return void */ public function log($message, array $scope) { echo "$message\n"; } } $dsn = "..."; $username = "..."; $password = "..."; $logger = new Logger(); $pdo = new PDOExcavated( $dsn, $username, $password, [ PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDOExcavated::ATTR_DEBUG => [ 'logger' => $logger, /** * Defaults. * * @see deepeloper\PDO\ExcavatingTrait::$debuggingOptions */ 'format' => [ 'timeStamp' => "Y-m-d H:i:s", 'count' => "%03d", 'precision' => "%.05f", 'call' => "[ %TIME_STAMP% ] [ %DSN%;user=%USER_NAME% ] [ %EXECUTION_TIME% ] [ CALL ] [ %SOURCE%(%ARGS%) ]", 'query' => "[ %TIME_STAMP% ] [ %DSN%;user=%USER_NAME% ] [ %EXECUTION_TIME% ] [ QUERY ] [ #%COUNT% ] [ %SOURCE% ] [ %QUERY% ]", ], 'sources' => [ ], ], ] ); $pdo->exec("UPDATE `test` SET `foo` = 0"); $stmt = $pdo->query("SELECT 1"); $stmt->fetch(); $stmt = $pdo->prepare("SELECT ?"); $stmt->bindValue(1, 100500, PDO::PARAM_INT); $stmt->execute();
将输出
[ ****-**-** **:**:** ] [ $dsn;user=$username ] [ *.***** ] [ CALL ] [ PDOExcavated::__construct(["$dsn","$username"]) ]
[ ****-**-** **:**:** ] [ $dsn;user=$username ] [ *.***** ] [ QUERY ] [ #001 ] [ PDOExcavated::exec ] [ UPDATE `test` SET `foo` = 0 ]
[ ****-**-** **:**:** ] [ $dsn;user=$username ] [ *.***** ] [ QUERY ] [ #002 ] [ PDOExcavated::query ] [ SELECT 1 ]
[ ****-**-** **:**:** ] [ $dsn;user=$username ] [ *.***** ] [ CALL ] [ PDOExcavated::prepare(["SELECT ?"]) ]
[ ****-**-** **:**:** ] [ $dsn;user=$username ] [ *.***** ] [ QUERY ] [ #003 ] [ PDOStatementExcavated::execute ] [ SELECT 100500 ]
如果您只想记录查询,请传递以下'sources'部分
'sources' => [ "/^PDOExcavated::(?:exec|query)/", "/^PDOStatementExcavated::execute/", ],
如果源以"/"开头,它将被处理为正则表达式,否则将被视为字符串。
自定义调试
您可以自定义日志消息范围,并在记录之前处理结果消息。
use deepeloper\PDO\LoggerInterface; use deepeloper\PDO\PDOExcavated; use deepeloper\PDO\PDOStatementExcavated; class class PDOExcavatedExtended extends PDOExcavated { /** * Allows to customize log message scope. * * @param array &$scope * @return void * @see ExcavatingTrait::after() */ protected function scope(array &$scope) { $scope['FOO'] = __METHOD__; } /** * Prepares query for logging. * * @param string &$query * @return void * @see ExcavatingTrait::after() */ protected function prepareQueryForLogging(&$query) { // Modify query here. } /** * Method used to replace PDOStatementExcavated by possible child. * * @param string $template * @param PDOStatementExcavated $stmt * @return PDOStatementExcavatedExtended * @see self::getResultStatement() */ protected function getStatement($template, PDOStatement $stmt) { return new PDOStatementExcavatedExtended($template, $this, $stmt); } } class PDOStatementExcavatedExtended extends PDOStatementExcavated { /** * Allows to customize log message scope. * * @param array &$scope * @return void * @see ExcavatingTrait::after() */ protected function scope(array &$scope) { $scope['FOO'] = __METHOD__; } /** * Prepares query for logging. * * @param string &$query * @return void * @see ExcavatingTrait::after() */ protected function prepareQueryForLogging(&$query) { // Modify query here. } } class Logger implements LoggerInterface { /** * Logs message. * * @param string $message * @param array $scope * @return void */ public function log($message, array $scope) { echo "$message\n"; } } $dsn = "..."; $username = "..."; $password = "..."; $logger = new Logger(); $pdo = new PDOExcavatedExtended( $dsn, $username, $password, [ PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDOExcavated::ATTR_DEBUG => [ 'logger' => $logger, 'format' => [ 'call' => "%FOO%", 'query' => "%FOO%", ], ], ] ); $pdo->exec("UPDATE `test` SET `bar` = ''"); $pdo->query("SELECT 1"); $stmt = $pdo->prepare("SELECT ?, ?"); $stmt->bindValue(1, 100500, PDO::PARAM_INT); $stmt->bindValue(2, "blah"); $stmt->execute();
将输出
deepeloper\PDO\PDOExcavatedExtended::scope
deepeloper\PDO\PDOExcavatedExtended::scope
deepeloper\PDO\PDOExcavatedExtended::scope
deepeloper\PDO\PDOExcavatedExtended::scope
deepeloper\PDO\PDOStatementExcavatedExtended::scope