<span><span><span class="hljs-meta"><?php</span></span><span>
</span><span><span class="hljs-comment">// This part is unrelated to the main topic</span></span><span>
</span><span><span class="hljs-keyword">echo</span></span><span> </span><span><span class="hljs-string">"Welcome to my PHP study notes!\n"</span></span><span>;
</span><span><span class="hljs-variable">$today</span></span><span> = </span><span><span class="hljs-title function_ invoke__">date</span></span><span>(</span><span><span class="hljs-string">"Y-m-d"</span></span><span>);
</span><span><span class="hljs-keyword">echo</span></span><span> </span><span><span class="hljs-string">"Today's date is: <span class="hljs-subst">$today</span></span></span><span>\n";
</span></span>
When working with PHP for database operations, especially when using the mysqli extension with prepared statements, performance optimization is often overlooked. This article explains how to combine mysqli_stmt::$field_count and mysqli_stmt::bind_result to improve query efficiency while maintaining code readability and security.
The $field_count property returns the number of fields in the current prepared statement’s result set. This is particularly useful in scenarios where SQL queries are generated dynamically or the number of fields is unknown. With it, you can bind result variables without knowing field names in advance.
Example:
<span><span><span class="hljs-variable">$stmt</span></span><span> = </span><span><span class="hljs-variable">$mysqli</span></span><span>-></span><span><span class="hljs-title function_ invoke__">prepare</span></span><span>(</span><span><span class="hljs-string">"SELECT id, name, email FROM users WHERE status = ?"</span></span><span>);
</span><span><span class="hljs-variable">$stmt</span></span><span>-></span><span><span class="hljs-title function_ invoke__">bind_param</span></span><span>(</span><span><span class="hljs-string">"s"</span></span><span>, </span><span><span class="hljs-variable">$status</span></span><span>);
</span><span><span class="hljs-variable">$stmt</span></span><span>-></span><span><span class="hljs-title function_ invoke__">execute</span></span><span>();
<p></span>// Get field count<br>
$fieldCount = $stmt->field_count;<br>
echo "This query returned $fieldCount fields.";<br>
</span>
With $field_count, you can process result sets dynamically without knowing field names, improving code flexibility.
Normally, we bind each field manually using bind_result:
<span><span><span class="hljs-variable">$stmt</span></span><span>-></span><span><span class="hljs-title function_ invoke__">bind_result</span></span><span>(</span><span><span class="hljs-variable">$id</span></span><span>, </span><span><span class="hljs-variable">$name</span></span><span>, </span><span><span class="hljs-variable">$email</span></span><span>);
</span></span>
If there are many fields, or if the fields change often, this becomes inefficient and error-prone. By combining $field_count with metadata, we can bind dynamically:
<span><span><span class="hljs-comment">// Get result metadata</span></span><span>
</span><span><span class="hljs-variable">$meta</span></span><span> = </span><span><span class="hljs-variable">$stmt</span></span><span>-></span><span><span class="hljs-title function_ invoke__">result_metadata</span></span><span>();
</span><span><span class="hljs-variable">$fields</span></span><span> = [];
</span><span><span class="hljs-variable">$bindVars</span></span><span> = [];
<p></span>// Dynamically create variables based on field count<br>
while ($field = $meta->fetch_field()) {<br>
$fields[] = $field->name;<br>
$bindVars[] = &${$field->name}; // Note the reference<br>
}</p>
<p>// Dynamically bind results<br>
call_user_func_array([$stmt, 'bind_result'], $bindVars);</p>
<p>// Fetch data<br>
$results = [];<br>
while ($stmt->fetch()) {<br>
$row = [];<br>
foreach ($fields as $field) {<br>
$row[$field] = ${$field};<br>
}<br>
$results[] = $row;<br>
}</p>
<p>print_r($results);<br>
</span>
This way, no matter how many fields are returned, the results are efficiently stored in an array, avoiding manual binding changes and improving maintainability and performance.
Less repetitive code: No need to manually write bind_result for every query, especially useful when fields change frequently.
Improved efficiency: Avoids repeated use of associative arrays and fetch_assoc(), retrieving data directly via bound variables.
Greater flexibility: Works well with dynamically generated SQL queries or when automatically fetching field names from tables.
When using dynamic binding, be sure to use references (&), otherwise values will not be retrieved correctly.
For large result sets, bind_result is more memory-efficient than fetch_assoc because it binds data directly to variables instead of creating full arrays.
For small queries, manually binding fields may not show noticeable performance differences, but dynamic binding is highly advantageous when fields are uncertain or queries change often.
By combining mysqli_stmt::$field_count and mysqli_stmt::bind_result, you can implement an efficient, flexible, and maintainable solution for prepared statement queries. It not only reduces code duplication but also enhances performance in large datasets and dynamic query scenarios—making it a valuable technique for PHP developers.