prepare()->execute() в обход query() (как в Repository). */ class Statement extends PDOStatement { /** @var array Значения, забинженные через bindValue()/execute() */ protected array $_bound_params = []; /** * @var bool Не логировать этот execute() в Profiler — для служебных запросов вроде EXPLAIN * внутри самой панели (ProfilerToolbar), которые иначе засоряли бы её же счётчик SQL. */ public bool $skip_profiling = false; /** * Конструктор вызывается только изнутри PDO (PDO::ATTR_STATEMENT_CLASS) — не создавать напрямую. * * @param PdoConnection $connection Владелец, нужен для quote() в showQuery() */ protected function __construct(protected PdoConnection $connection) { } /** * @inheritDoc */ public function bindValue(int|string $param, mixed $value, int $type = PDO::PARAM_STR): bool { $this->_bound_params[$param] = $value; return parent::bindValue($param, $value, $type); } /** * @inheritDoc */ public function execute(?array $params = null): bool { foreach ($params ?? [] as $key => $value) { $this->_bound_params[$key] = $value; } $start = microtime(true); $result = parent::execute($params); if (!$this->skip_profiling) { Profiler::log($this->queryString, $this->_bound_params, (microtime(true) - $start) * 1000); } return $result; } /** * Возвращает SQL с подставленными вместо плейсхолдеров значениями — только для дебага * (не для реального выполнения: значения квотируются через PDO::quote(), не защищают от всего, * на что рассчитана честная подготовленная подстановка). * * @return string * @throws \System\Classes\MyException */ public function showQuery(): string { $sql = $this->queryString; foreach ($this->_bound_params as $key => $value) { $quoted = is_int($value) || is_float($value) ? (string) $value : $this->connection->pdo()->quote((string) $value); if (is_int($key)) { $pos = strpos($sql, '?'); if ($pos !== false) { $sql = substr_replace($sql, $quoted, $pos, 1); } } else { $placeholder = str_starts_with((string) $key, ':') ? $key : ':' . $key; $sql = str_replace($placeholder, $quoted, $sql); } } return $sql; } /** * Алиас showQuery() для быстрого дебага. * * @return string * @throws \System\Classes\MyException */ public function sq(): string { return $this->showQuery(); } }