Я наткнулся на этот вопрос два года назад.
Есть ли способ получить необработанную строку SQL, выполняемую при вызове PDOStatement :: execute () в подготовленном заявлении? Для целей отладки это было бы чрезвычайно полезно.
- Команды не синхронизированы; вы не можете запустить эту команду сейчас, когда вызываете хранимую процедуру в Mysql
- Ограничение доступа IFRAME в PHP
- Как проверить, есть ли запрос, поступающий с того же сервера или другого сервера?
- Как получить список процессов PHP, работающих на сервере с PHP
- DOMPDF - добавьте созданный PDF в электронную почту
В выигрышном ответе говорится, что
[…] Вы также можете получить то, что хотите, если вы установите атрибут PDO PDO :: ATTR_EMULATE_PREPARES. В этом режиме PDO интерполирует параметры в SQL-запрос и отправляет весь запрос при выполнении ().
Но он не упоминает, как получить полученную строку запроса. Я знаю, что это плохая идея, но это не мешает мне в режиме отладки. Кто-нибудь знает, как это сделать?
PS Если есть какой-то способ, я мог бы снова открыть / обратить внимание на оригинальную двухлетнюю тему вместо того, чтобы открывать новую, пожалуйста, дайте мне знать.
Я считаю, что это упоминается в первоначальном вопросе, который был ссылкой в этом. Однако на самом деле предполагается, что это метод для извлечения этих данных.
PDOStatement::debugDumpParams
Однако в настоящее время он не документируется. Для этого есть сообщение об ошибке и патч, представленный здесь http://bugs.php.net/bug.php?id=52384, если кто-то заинтересован в голосовании по нему. Пока это не исправлено, кажется, что вам осталось использовать ведение журнала запросов или настройку класса пользовательских операторов с использованием атрибута PDO :: ATTR_STATEMENT_CLASS.
Afaik, PDO на самом деле не раскрывает его вам. На серверах разработки вы можете включить общий журнал запросов для MySQL (если это то, что вы используете), возможно, с большим контролем с sql_log_off , что требует привилегии SUPER.
Если вы не можете получить его из самого PDO, рассмотрите возможность использования класса-оболочки только для PDOStatement::execute()
который будет регистрировать SQL-запрос и значения, а затем вызывать execute()
в инструкции. Вам придется реорганизовать свой код, чтобы использовать новый класс.
В качестве побочного элемента я вижу, что в PDOStatement есть переменная класса $queryString
которая содержит используемый запрос. Значения должны быть получены из того, что передано в execute()
или bindParam()
.
Сначала некоторые функции утилиты для ведения журнала:
//removes newlines and extra spaces from print_r output function str_squeeze($str) { if (is_array($str)) { $str = print_r($str, true); } $str = preg_replace('/[(\r)?\n|\t]/', ' ', $str); $str = trim(ereg_replace(' +', ' ', $str)); return $str; } function logger($str) { //log it somewhere }
class My_PDO_Utils { public static function execute(PDOStatement &$stm, $values = array()) { logger("QUERY: " . $stm->queryString . ", values = " . str_squeeze($values)) ; return $stm->execute($values) ; } }
Тогда ваш код должен быть:
$stm = $db->prepare("SELECT * FROM table2 WHERE id = ?") ; $res = My_PDO_Utils::execute($stm, array(79)) ;
вместо
$res = $stm->execute(array(79)) ;
Подумав еще об этом, вы могли бы принять это еще одно:
Если вы хотите быть предприимчивым, вы можете расширить PDOStatement, чтобы выполнить регистрацию для вас, и PDO, чтобы вернуть ваш расширенный класс PDOStatement. Это потребует наименьшего возможного рефакторинга, то есть просто измените new PDO()
на new MY_PDO()
, но может оказаться сложным в его реализации, поскольку вам нужно будет явно определить любую функциональность PDOStatement, которая вам нужна в MY_PDOStatement, чтобы она вызывалась должным образом.
class My_PDO extends PDO { public function prepare($sql, $options = array()) { //do normal call $stm = parent::prepare($sql, $options) ; //encapsulate it in your pdostatement wrapper $myStm = new My_PDOStatement() ; $myStm->stm = $stm ; return $myStm ; } } class My_PDOStatement extends PDOStatement { /** * * @var PDOStatement */ public $stm ; public function execute($values) { logger("QUERY: " . $this->stm->queryString . ", values = " . str_squeeze($values)) ; return $this->stm->execute($values) ; } public function fetchAll($fetch_style = PDO::FETCH_BOTH, $column_index = 0, $ctor_args = array()) { return $this->stm->fetchAll($fetch_style, $column_index, $ctor_args) ; } }
Но теперь ваш код может быть:
$db = new My_PDO($dsn, $user, $pass) ; $stm = $db->prepare("SELECT * FROM table2 WHERE id = ?") ; $res = $stm->execute(array(79)) ; $row = $stm->fetchAll() ;
Самый лучший подход, на мой взгляд, заключается в использовании журнала mysql для отображения последних запросов, поскольку получение их непосредственно в php является перетаскиванием.
From Как показать последние запросы, выполняемые в MySQL? первый ответ:
Кроме того, для тех, кто благословлен MySQL> = 5.1.12:
SET GLOBAL log_output = 'TABLE'; SET GLOBAL general_log = 'ON';
Взгляните на таблицу mysql.general_log Если вы предпочитаете выводить в файл:
SET GLOBAL log_output = "FILE"; which is set by default. SET GLOBAL general_log_file = "/path/to/your/logfile.log" SET GLOBAL general_log = 'ON';
Я предпочитаю этот метод, потому что:
вы не редактируете файл my.cnf и, возможно, постоянно включаете ведение журнала, вы не ловите рыбу вокруг файловой системы, которая ищет журнал запросов – или, что еще хуже, отвлекается на необходимость идеального назначения. / var / log / var / data / log / opt / home / mysql_savior / var перезагрузка сервера оставляет вас там, где вы начали (журнал отключен) Дополнительные сведения см. в Справочном руководстве MySQL 5.1 – Системные переменные сервера – general_log
Следующий статический метод принимает шаблон запроса PDO (SQL-запрос с :name
?
И / или :name
) и интерполирует параметры:
static public function getDebugFullQuery($query, $params = array()){ if(is_array($params) && count($params)){ $search = []; $replace = []; foreach($params as $k => $p){ $pos = strpos($query, ":{$k}"); if($pos !== false){ $query = substr($query, 0, $pos) . "%!-!{$k}!-!%" . substr($query, $pos + strlen($k) + 1); } else { $pos = strpos($query, "?"); if($pos !== false){ $query = substr($query, 0, $pos) . "%!-!{$k}!-!%" . substr($query, $pos + 1); } else { break; } } $search[] = "%!-!{$k}!-!%"; $replace[] = "'" . str_replace(array("\r", "\n", "'"), array("\\\\r", "\\\\n", "\\'"), $p) . "'"; } if(count($search)){ $query = str_replace($search, $replace, $query); } } return $query; }
Как указано в имени метода, вы должны использовать это только для целей отладки.