Your question addresses an interesting subject, in my opinion.
By a rapid search, I don't have found any predefined solution, but I will continue search in the next days.
I have elaborate a solution, but it is a bit twisted and not totally clean.
First of all, I redefine the query with placeholders:
$query = "
INSERT INTO table
(
tag,
month_interval,
month_interval_lastupdated,
date_due,
date_due_lastupdated,
date_completion,
date_completion_lastupdated,
activeNotification,
date_lastmodified
)
VALUES (<tag>,<month_interval>,NOW(),<date_due>,NOW(),<date_completion>,NOW(),<activeNotification>,NOW())
";
In this example, I use <>
to surround placeholder, but you can choose your preferred placeholder, making sure that they do not confuse with others elements of the query.
Then, I init an associative array with keys as placeholders names and values to be bind, and a variable ($types
) with the complete set of bind types:
$values = array( 'tag'=>$tag, 'month_interval'=>$month_interval, 'date_due'=>$date_due, 'date_completion'=>$date_completion, 'activeNotification'=>$activeNotification );
$types = 'sisss';
Then, the most important line. I init an array in this strange way:
$bind = array( Null, '' );
The index 0 is set to Null
, because is reserved for the stmt
object (created below); the index 1 is an empty string that will be filled with necessary bind types.
Now I perform a foreach
loop through all elements of array $values
:
$i = 0;
foreach( $values as $key => $val )
{
if( is_null( $val ) )
{
$query = str_replace( '<'.$key.'>', 'DEFAULT', $query );
}
else
{
$query = str_replace( '<'.$key.'>', '?', $query );
$bind[1] .= $types[$i];
$bind[] = &$val;
}
$i++;
}
In that loop, if the value is null I replace the corresponding query's placeholder with mySQL keyword DEFAULT
. Otherwise, I replace placeholder with a ?
, I add the corresponding $types
substring to $bind[1]
, and I append the value (by reference) to $bind
array.
At this point, the real query is ready to go, and I can prepare it:
$stmt = $db->prepare( $query ) or die( $stmt->error );
and, if there are not default values (count($bind)>2
), I can bind it:
if( count($bind)>2 )
{
$bind[0] = $stmt;
call_user_func_array( 'mysqli_stmt_bind_param', $bind );
}
As said before, I set $bind[0]
to stmt object returned by ->prepare
, then I use call_user_func_array
to perform mysqli_stmt_bind_param
. I can't directly call ->bind_param
because I have a variable arguments number.
At the end of this eccentric process, finally I can execute the query:
$stmt->execute() or die( $stmt->error );
I have tested this code, and it works.
The main problem reside in the is_null( $val )
: using an array, I can't use isset
as test, because every element of an array is even set. The code works if all the field with placeholder that allows Null value has Null ad default value.