使用PDO更乏味的一点是它说缺少一些变量
PDOStatement :: execute():SQLSTATE [HY093]:参数号无效:绑定变量数与令牌数不匹配
......但不知道哪些。是否有任何解决方案来识别它们?例如
$sql = "SELECT id, name WHERE id = :id AND name like :search_tem";
$stmt = $pdo->prepare($sql);
$stmt->bindValue(':id', '1');
$stmt->execute(); // throws exception - "**search_term missing"
很明显每个人都需要这样的东西。但我不能简单解决。
答案 0 :(得分:2)
由于声誉不佳,我无法直接评论。所以想象一下这是对13年1月19日15:58对Ragen Dazs的回复。 我知道这个话题已经有几天了,但如果像我这样的人通过谷歌搜索偶然发现...
然而,我在第三行的正则表达式中遇到了问题。正如您在this example中所看到的,表达式还将时间值与00:00:00作为时间进行匹配。所以我建议使用此example中的正则表达式。
我也想知道是否有不必要的参数。我就是这样做的,它需要一个像上面例子中的那个SQL查询和一个参数数组(参见php doc example#2 for PDOStatement::execute)。
/**
* Checks an parameter array against the sql query. it will tell you if there are any missing or needless parameters
*
* @param string $query Sql query
* @param array $parameters Parameters array
*
* @return bool|array Returns TRUE if no missing or needless parameters where found or a list with the missing
* or needless parameters
*/
private function checkParameters($query, $parameters)
{
$parameterTMP = $parameters;
$parameterCount = count($parameterTMP);
$regexMatchCounter = preg_match_all("/:[^]\\D\\w*/", $query, $regexMatches);
// if there are parameter in the $parameters array oder parameters in the sql query
if( $parameterCount > 0 || $regexMatchCounter > 0 )
{
// take every parameter found in the sql query
foreach( $regexMatches[ 0 ] as $parameterName )
{
// check if the required parameter is in the parameters array
if( !array_key_exists($parameterName, $parameters) )
{
// if it is not in the parameters array, add it to the list of missing parameters
// and continue with the next parameter from the query
$result[ 'missing' ][] = $parameterName;
continue;
}
// if the required parameter is in the parameter array, delete it from this array
// so we get a list of parameters that are needless
unset($parameterTMP[ $parameterName ]);
}
// check if there are (needless) parameters left
if( count($parameterTMP) > 0 )
{
// if so, add them to the list of needles parameters
$result[ 'needless' ] = array_keys($parameterTMP);
}
// if at this point $result is an array,
// some parameters are missing or needless, so we return the result list(s)
if( isset($result) && is_array($result) )
{
return $result;
}
}
// if we reach this point, no missing or needless parameters where found,
// you are good to go
return true;
}
如果有人想让它在出现问题时抛出异常,只需替换“return $ result;”使用以下代码行:
$missingCount = 0;
$missing = "";
$needlessCount = 0;
$needless = "";
if( array_key_exists('missing', $parameters) )
{
$missingCount = count($parameters[ 'missing' ]);
$missing = " (" . implode(", ", $parameters[ 'missing' ]) . ") ";
}
if( array_key_exists('needless', $parameters) )
{
$needlessCount = count($parameters[ 'needless' ]);
$needless = " (" . implode(", ", $parameters[ 'needless' ]) . ")";
}
$msg = "There are " . $missingCount . " missing parameter(s)".$missing." and ".$needlessCount." needless parameter(s)".$needless.".";
throw new Exception($msg);
玩得开心。
答案 1 :(得分:1)
我想说,PDO团队发明了命名占位符,特别是为此目的 - 简化查询和占位符的可视化验证。
我不得不同意,这样的功能可能是某种语法错误糖,但老实说,我觉得它不太有用。还有其他错误更令人费解(如you have an error near ''
一个),而找到丢失的占位符并不是什么大问题。
答案 2 :(得分:1)
经过几天搜索这个主题,测试一些我发现这个解决方案的东西 - 按照我的数据库类中bind
方法的代码:
// [Method from Class Database]
/**
* @param PDOStatement stmt
* @param array data
* @throws Exception if some variables are missing when interpolate query
* @example $db->bind($stmt, $_POST)
*/
function bind(&$stmt, $data) {
$sql = $stmt->queryString;
// Sort $data keys to prevent erroneus bind parameters
ksort($data);
$data = array_reverse($data);
foreach ($data as $_key => $_val) {
if (preg_match("/:$_key/", $sql)) {
$stmt->bindParam(":$_key", $data[$_key]);
$sql = preg_replace("/:$_key/", $this->dbh->quote($data[$_key]), $sql, 1);
}
}
// if ($this->debug) {
// $this->fb->info($sql, 'SQL');
// $this->fb->info($stmt, 'Statment');
// $this->fb->info($data, 'Raw Data');
// }
if (strpos($sql, ":")) {
$matches = array();
$this->dbg = preg_match_all('/:[A-Za-z0-9_]*/', $sql, $matches);
throw new Exception('PDO Missing variables: ' . implode(', ', $matches[0]));
}
}
此代码需要修改,如果有人发现错误或改进了某些内容请分享!
答案 3 :(得分:0)
第一次误读了这个问题,我现在可以理解你想要的是什么了。据我所知,这是不可能的,因为错误消息是由PDO Exception定义的。
但是,解决方法可能是为PDO编写包装类,并检查绑定值并自行查询,然后如果有缺失值,则抛出自己的异常。这可能是实现这一目标的最佳方式......
很明显每个人都需要这样的东西。但我不能 简单的解决方案。
我不同意这一点,添加这种功能将毫无意义。考虑一下:
"SELECT id, name WHERE id = '1' AND name like "
这是您的代码在允许的情况下输出的内容!显然,上述内容不可以正常工作,因为LIKE
一词中没有任何内容。
我可以理解为什么你想要这个,因为我也忘记了(有意无意地)过去绑定值,但实际上没有任何好处,因为如果不绑定值,查询将无法正常工作。
最好动态构建查询,如下所示:
// Gather the where parameters
$get_data_where = array();
// Field 2
if(!empty($parameters['field_1'])){
$get_data_where[':field_1'] = '%'.$parameters['field_1'].'%';
}
// Field 2
if(!empty($parameters['field_2'])){
$get_data_where[':field_2'] = $parameters['field_2'];
}
// Combine the where array with the bind valus array
$this->mssql->bind_values = array_merge($this->mssql->bind_values,$get_data_where);
// Prepare the SQL to gather the data
$SQL = "SELECT * \n";
$SQL .= "FROM [Some_Table] AS ST \n";
// Append the where statement if necessary
// Build the where statement based on bind values
if(!empty($get_data_where)){
$SQL .= "WHERE \n\t";
// Field 1
if(!empty($this->mssql->bind_values[':field_1'])){
$SQL .= $where_and."ST.[Field_1] LIKE :field_1 \n\t";
// Separate the where conditions
$where_and = "AND ";
}
// Field 2
if(!empty($this->mssql->bind_values[':field_2'])){
$SQL .= $where_and."ST.[Field_2] = :field_2 \n\t";
// Separate the where conditions
$where_and = "AND ";
}
}