I’m completely new to Mysqli (switching over from MySQL), so to keep things simple, safe, and secure, would it make sense to run absolutely ALL Mysqli queries through this one-size-fits-all function?
Why or why not and what would be the Pros and Cons either way?
function mysqli_prepared_query($link,$sql,$typeDef = FALSE,$params = FALSE){
if($stmt = mysqli_prepare($link,$sql)){
if(count($params) == count($params,1)){
$params = array($params);
$multiQuery = FALSE;
} else {
$multiQuery = TRUE;
}
if($typeDef){
$bindParams = array();
$bindParamsReferences = array();
$bindParams = array_pad($bindParams,(count($params,1)-count($params))/count($params),"");
foreach($bindParams as $key => $value){
$bindParamsReferences[$key] = &$bindParams[$key];
}
array_unshift($bindParamsReferences,$typeDef);
$bindParamsMethod = new ReflectionMethod('mysqli_stmt', 'bind_param');
$bindParamsMethod->invokeArgs($stmt,$bindParamsReferences);
}
$result = array();
foreach($params as $queryKey => $query){
foreach($bindParams as $paramKey => $value){
$bindParams[$paramKey] = $query[$paramKey];
}
$queryResult = array();
if(mysqli_stmt_execute($stmt)){
$resultMetaData = mysqli_stmt_result_metadata($stmt);
if($resultMetaData){
$stmtRow = array();
$rowReferences = array();
while ($field = mysqli_fetch_field($resultMetaData)) {
$rowReferences[] = &$stmtRow[$field->name];
}
mysqli_free_result($resultMetaData);
$bindResultMethod = new ReflectionMethod('mysqli_stmt', 'bind_result');
$bindResultMethod->invokeArgs($stmt, $rowReferences);
while(mysqli_stmt_fetch($stmt)){
$row = array();
foreach($stmtRow as $key => $value){
$row[$key] = $value;
}
$queryResult[] = $row;
}
mysqli_stmt_free_result($stmt);
} else {
$queryResult[] = mysqli_stmt_affected_rows($stmt);
}
} else {
$queryResult[] = FALSE;
}
$result[$queryKey] = $queryResult;
}
mysqli_stmt_close($stmt);
} else {
$result = FALSE;
}
if($multiQuery){
return $result;
} else {
return $result[0];
}
}
?>
Example(s):
For a table of firstName and lastName:
John Smith
Mark Smith
Jack Johnson
Bob Johnson
<?php
//single query, single result
$query = "SELECT * FROM names WHERE firstName=? AND lastName=?";
$params = array("Bob","Johnson");
mysqli_prepared_query($link,$query,"ss",$params)
/*
returns array(
0=> array('firstName' => 'Bob', 'lastName' => 'Johnson')
)
*/
//single query, multiple results
$query = "SELECT * FROM names WHERE lastName=?";
$params = array("Smith");
mysqli_prepared_query($link,$query,"s",$params)
/*
returns array(
0=> array('firstName' => 'John', 'lastName' => 'Smith')
1=> array('firstName' => 'Mark', 'lastName' => 'Smith')
)
*/
//multiple query, multiple results
$query = "SELECT * FROM names WHERE lastName=?";
$params = array(array("Smith"),array("Johnson"));
mysqli_prepared_query($link,$query,"s",$params)
/*
returns array(
0=>
array(
0=> array('firstName' => 'John', 'lastName' => 'Smith')
1=> array('firstName' => 'Mark', 'lastName' => 'Smith')
)
1=>
array(
0=> array('firstName' => 'Jack', 'lastName' => 'Johnson')
1=> array('firstName' => 'Bob', 'lastName' => 'Johnson')
)
)
*/
I’m sorry, but no I think it’s a terrible idea.
A good function/method should be short, to the point, and designed to do one thing and only one thing well. It should also try to avoid branching logic where possible (keep the number of if and switch statements to a minimum). Such functions are easy to understand as their inner workings can be grasped with relatively little effort.
The longer a function is, the harder it becomes to understand because the programmer has to hold more in their head regarding how it works. The more if/switch/try/catch/throw statements the function contains, the harder it becomes to understand because they modify how execution might flow through the function. You have to take into account something known as the npath complexity (a count of the possible ways a function can execute). Every if you add will double the npath complexity. Based purely on counting ifs I got a complexity of 64, which is far too high! Loops can increase npath complexity as well, so the actual complexity metric for your function is probably a lot higher than that.
Changing a function like the one you’ve given becomes far more work than it would be if it was a collection of smaller simple functions, because it’s very difficult to make a particular change to achieve the intended new behaviour without having unwanted knock-on effects. Of course you can use a unit test to make sure that this doesn’t happen, but with a high npath complexity, the number of tests you’ll have to write to make sure the functionality of your function is fully covered is inordinately large.
Good general rules of thumb:
A much better solution would be to implement a class that provides the services you need as a series of methods.
An even better solution would be to check how much of this PHP can do through its built in functionality for you. As I can’t really understand your function I couldn’t say for sure whether PHP can already do what you need this function to do, but my suspicion is that a good chunk of it is already implemented in PHP.