php の pdo でエラーがでるので数日ずっと頭を抱えてた
出てくるエラー
: Invalid parameter number: number of bound variables does not match number of tokens
エラーは、php pdo の prepare statement で、execした時にエラーになる。
<?php /// できる $stmt->bindValue(":n1", $val ); $stmt->bindValue("n1", $val ); $stmt->bindValue("123n", $val ); /// 出来ない $sth->bindValue(':123', $val ); $sth->bindValue('123', $val );
エラーに気づかないわけ。
bindValue( $key, $value )
は $key が文字列だと、文字列インデックスでバインドし、ハッシュ :name
から文字列キーを探す。
ところが、「数字に解釈できる文字列」だと、数字だと思って疑問符( = ?
)に入れようと、該当の疑問符の数字インデックスを探す→見つからない→bindParamがありません。エラーとなる。
<?php $sth->bindValue('123', $calories); // $sth->bindValue(':123', $calories); // 123 番目を探しに行く
内部で$params[123]
を探しに行く。そんなものあるわけがない。探してほしいのは $params[":123"]
なんだよね
指定したけどintになる文字列だと、?
を探しちゃってbindValue指定時のキーに入れられない。だからエラーになる。
しかもexecするまでわからない。(←ここが辛い)
コード作者はちゃんと値を入れてるから、値がないなんて考えないよね。でもbindValueエラーが出るんだよね。頭抱えるよね。
対策
文字列であることを明確にする
<?php $key="123" $sth->bindValue($key.'__', $v );
型変換怖い
原因がわかればなんてことないが、php7以降は「型」に強いと思ってると痛い目に遭う。
組み込み関数の型は相変わらず、自動変換される。phpは自動型推測で動いたのに、いまはソースコードに型を明示するようになったので、本当に気づかない。
とくに、SQLを自動生成してるとこのバグを踏みまくる。 随分前にこの仕様を踏んでめっちゃ頭を抱えた記憶があるのだが、7−8年越しにまた踏んで頭を抱えたので、メモ。
ここ数年はLaravelしか使わないし、PDOを素で使うことなんてないからこういうのすっかり忘れてハマりました。