準備済みステートメントは、プロトコル機能 (mysql など) であるか、舞台裏で C ライブラリで実行されます。つまり、ステートメントを解析する作業は PDO コードによって行われません。これは、データベース サーバーまたは libsqlite のような C ライブラリによって行われます。PDO はそれ自体でステートメントを解析せず、それを下位レベルのコンポーネントに渡すだけなので、param 情報は使用できません。
そのため、プレーンな PHPを使用すると、PDOStatement オブジェクトを使用したクエリで関連付けプレースホルダー => 値に置き換えられません。これは、準備済みステートメントの設計によるものです。
PDOStatement
回避策として、param プレースホルダーを現在のクエリ文字列の値で置き換えるメソッドを拡張して追加することが考えられます。以下に例を用意しました。この例は:bar
、引用符で囲まれた文字列で発生した場合でも置換されるため、防弾ではないことに注意してください。しかし、内部で使用する場合、このようなソリューションはこれまでのところ私にとって良い仕事をしてくれました.
カスタム ステートメント クラス:
class MyStatement extends PDOStatement
{
protected $params;
protected $pdo;
protected function __construct($pdo) {
$this->pdo = $pdo;
}
public function execute($params = null) {
$this->params = $params;
return parent::execute($params);
}
public function printQuery(){
$_params = $this->params;
$sql = $this->queryString;
foreach($this->params as $key => $value) {
$_value = is_null($value) ?
'NULL' : '\'' . $value . '\'';
$sql = str_replace(':'. $key, $_value, $sql);
}
return $sql;
}
}
変更された PDO が必要です:
class MyPDO extends PDO
{
public function __construct($dsn, $username="", $password="", $driver_options=array()) {
parent::__construct($dsn, $username, $password, array(
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_STATEMENT_CLASS => array('MyStatement', array($this))
));
}
}
テストコード:
$pdo = new MyPDO('mysql:host=localhost;dbname=test', 'root', '******');
// preapre stupid query
$stmt = $pdo->prepare('SELECT FROM `foo` WHERE name = :bar');
try {
// execute stmt
$stmt->execute(array('bar' => 'hek2mgl'));
} catch (PDOException $e) {
echo $stmt->printQuery();
}