问题
I know: this has been done to death.
But, believe me, I've been researching for quite a while on how to fix this one. What I'm trying to achieve is a PDO MySQL Database wrapper for use with PDO that I can just incorporate into my code. My main problem stems from two functions in particular, as well as the actual binding of the parameters I'm trying to reach. The reason why I state two functions as opposed to one is, despite my efforts, I haven't been able to spot which one is attempting the problem. The variable's I've var_dump
ed have confirmed that it's not the variable, it's something else. Still, the fact that I'm getting this error in first place means that something has to be wrong with the code.
Exhibit A: fetch( $table, $columns, $whereArgs )
The purpose of this function is to simply fetch a row. This is achieved by accepting the table of the row to fetch, along with whatever columns and where-clauses are needed in order to accomplish the task specifically. Once the parameters have been submitted one or two loops are invoked which dynamically form the query.
public function fetch( $table, $columns, $whereArgs )
{
if ( $whereArgs === NULL && $columns === NULL ) return false;
$select = "SELECT ";
$where = " WHERE ";
$iQuery = 0;
$sqlParams = array();
$columnCount = count( $columns ) - 1;
foreach( $whereArgs as $key => $value )
{
$paramKey = sprintf( ':%s', $key );
$where .= sprintf( "`%s`= %s", $key, $paramKey );
$sqlParams[ "{$paramKey}" ] = sprintf( "%s", $value );
if ( $iQuery <= $columnCount )
{
$select .= sprintf( '`%s`', $columns[ $iQuery ] );
$select .= ', ';
}
else
{
$select .= ' ';
}
++$iQuery;
}
if ( $iQuery <= $columnCount )
{
for( ; $iQuery < $columnCount; ++$iQuery )
{
if ( $iQuery < $columnCount )
{
$select .= sprintf( '`%s`', $columns[ $iQuery ] );
$select .= ', ';
}
else
{
$select .= ' ';
}
}
}
$select .= sprintf( "FROM `%s`", $table );
$query = $select . $where;
return $this->doQuery( $query, $sqlParams, TRUE, QueryType::Row );
}
Exhibit B: doQuery( $query, $sqlParams, $return = FALSE, $queryType = QueryType::None )
This function is relatively simple: all it does is bind values and execute the statement, while promptly checking for which type to return (the return types, which are either 'row', 'column', or 'all', are specified by the class QueryType
, a class which outside the scope of this issue), and then returning whatever is asked for.
protected function doQuery( $query, $sqlParams, $return = FALSE, $queryType = QueryType::None )
{
$statement = $this->mConnection->prepare( $query );
foreach( $sqlParams as $param => $value )
{
$statement->bindValue( $param, $value );
}
$statement->execute( );
if ( $return )
{
switch( $queryType )
{
case QueryType::Row:
return $statement->fetch( );
case QueryType::Column:
return $statement->fetchColumn( );
case QueryType::All:
return $statement->fetchAll( );
case QueryType::None:
return $statement;
default:
return false;
}
}
}
Exhibit C: test.php
This is simply a little test script I wrote to test the database.
$database = new Database( 'evolve_admin' );
$res = $database->fetch(
'evol_users',
array( 'user.id', 'user.email', 'user.firstname' ),
array( 'user.email' => 'test1234@test.com' )
);
var_dump( $res );
Other Comments
I've learned that there is something wrong with my code, I'm just lost as to what exactly it could be. As far as my debugging skills go, I have researched this issue quite a bit, and it seems that this error is very common. My main goal is to get this wrapper working, and if anyone sees any faults within the code itself (including ones which outside the scope of this issue in particular), please let me know.
To anyone who offers a hand in this one: thank you very much.
回答1:
I think you're forgeting some spaces there:
$where .= sprintf( "`%s`= %s", $key, $paramKey );
The next time you used the $wher
variable was when you append it to the $select
one.
If more that one where arg the where is :
WHERE `%s`= %s`%s`= %s`%s`= %s`%s`= %s`%s`= %s
You did not do the error with your SELECT generation thought.
BTW you have the two same loops ànd testfor your select generation if ( $iQuery <= $columnCount )
. One in the where loop and another outside. What is the use?
Edit: And of course i forgot to point out why you have this freaking error: It's in
$sqlParams[ "{$paramKey}" ] = sprintf( "%s", $value );
You create a table that will look like that: array ( "{:akey}" => "avalue")
(i considered the value as string.
Why did you use curly brackets ({} ), it completly change the key name (should be :keyname
not {:keyname
}
Edit 2: Was in a good mood so here is a simplified version of your fetch method.(not tested but should work fine)
/*
* $whereArgs default value is an array, so you can call a select
* without an empty array supplied if you does not have some where clause arguments
* The separator is how the element will be binded alltogether in the where clause
*/
public function fetch( $table, $columns, $whereArgs = array(), $separator= 'AND' )
{
/* We return false, if the columns variable is not set, or is not an array,
* or (if it is an array) does not contain anything
* or the $whereArgs is not and array (it would mean something bad have been given)
*/
if ( false == isset($columns) || false == is_array($columns)
|| 0 == count($columns) || false == is_array($whereArgs) )
{
return false;
}
$select = "SELECT";
$from = " FROM `$table`";
$where = " WHERE ";
/* SELECT generation */
for ( $columIt = 0; $columIt < count($columns); $columIt++)
{
$select .= " " . $columns[$columIt];
// We check if we need to add a ','
if ( $columIt+1 < count($columns) )
{
$select .= ",";
}
}
/* WHERE clause generation */
$sqlParams = array();
$whereIt = 0;
foreach( $whereArgs as $key => $value )
{
$stripedKey = preg_replace('/\\./', '_', $key);
$where .= " $key= :$stripedKey";
$sqlParams[ ":$stripedKey" ] = "$value";
// We check if we need to add a where separator
if ( $whereIt +1 < count($whereArgs ) )
{
$select .= " $separator";
}
$whereIt++;
}
/* the generated where clause is only printed if $whereArgs
* is not an empty array
*/
$query = $select . $from . ((0<count($whereArgs))?$where:"");
return $this->doQuery( $query, $sqlParams, TRUE, QueryType::Row );
}
Edit 3: BTW didn't see your test sample, but param name can't contain '.' char
Edit 4: Didn't see yous solved it, I added a pre_replace to replace the '.' in your subset. Also get rid of the '`' char when echoing the key, the query will fail otherwise
`user.email`=:arg
Is not liked =)
user.email=:arg or user.`email`=:arg
Prefered (`) is used to include special char in column name, so used like before, the column name didn't match to any existing one.
Edit 5: Instead of stripping your key to create your arguments and argument array. You could use a safe way what that prevent the apparition of misleading characheters, by taking advantage of the $whereIt counter:
$where .= " $key= :arg_$whereIt";
$sqlParams[ ":arg_$whereIt" ] = "$value";
Regards
回答2:
The problem was due to the fact that every column I had in my test db had a '.' between 'user' and the name of the column. I solved the problem by just replacing every period with an underscore, and that got rid of the error. While the query still isn't working for some reason, I'm sure things will be fine.
So, for example:
user.email
= user_email
.
来源:https://stackoverflow.com/questions/9961772/sqlstatehy093-invalid-parameter-number-parameter-was-not-defined-pdo