MySQLi fetch_all Error with Consecutive Calls - php

I've set up a class to handle my MySQLi calls. The calls are working as they should, so no problems there.
I recently removed the result handling from my class's query method to two separate setter methods. There is now an error resulting from two consecutive fetch_all calls.
The previous (working) code with a single fetch_all call loads results into the two arrays res_rows and res_cols:
// Convert results into two sets of values
// and store in properties
// $res_rows=results by row (column names in element 0)
// Each row is an indexed array
// $res_cols=results by column (associative arrays)
// Key is the column name; Value is an array
$results=$res->fetch_all(MYSQLI_ASSOC);
// $colNames is an array of the column names
$colNames=array_keys($results[0]);
// Rows
foreach($results as $r) {
$this->res_rows[]=array_values($r);
}
array_unshift($this->res_rows,$colNames);
// Columns
$vals=array();
// Count the number columns in the query
$numCols=count($colNames);
// Iterate through the columns
for($i=0;$i<$numCols;$i++) {
$col=$colNames[i];
$storage=array();
foreach($results as $r) {
$storage[]=$r[$colNames[$i]];
}
$vals[]=$storage;
}
$this->res_cols=array_combine($colNames,$vals);
I've moved this code into two methods setRes_rows and setRes_cols and called them sequentially (see code). Each method pulls results from the result object using fetch all.
$this->setRes_rows($res);
$this->setRes_cols($res);
What happens is that the first call behaves as expected, and the second call returns an empty array.
If I reverse the calls (e.g. setRes_cols first), the same thing happens (first call works as expected; second call is empty). So I know the code is good. I even changed all the variable names in one of the methods with no effect.
I dumped all properties and methods on the result object between calls and it doesn't look like it changes. But for some reason that second fetch_all does not work.
The easy fix is for me to use a single fetch_all then call my methods. But I'm interested in knowing if there's anything weird I'm missing.
Thanks, everyone.

It looks like you need to reset the result pointer after a fetch_all.
I didn't find anything in the docs specifically for fetch_all - only about resetting after a fetch_assoc(), where we can find a reference to data_seek(): http://php.net/manual/en/mysqli-result.data-seek.php
So here's what you should do:
before the second fetch_all() do a
$res->data_seek(0); // where $res is your mysqli result Object
This basicly sets the result pointer to the first record.

Related

PHP Gives Infinite While Loop when mysqli_fetch_assoc Expression is Replaced with just a Variable

I'm a complete newbie in PHP and I just don't understand how while loop works with mysqli_fetch_assoc. The former execute statements based upon expressions, the latter retrieves a row from the database. So if you don't end the loop, it will continue to iterate the field in the first row infinitely;
<?php
$connect_db=mysqli_connect('localhost','root','root','db');
$fetch_data="SELECT * FROM tabel";
$query_db=mysqli_query($connect_db,$fetch_data);
$fetch_row=mysqli_fetch_assoc($query_db);
while($fetch_row){
$column_2_array=$fetch_row['column_2'];
echo($column_2_array);
break;
}
?>
What I'm scratching my head is if the whole expression is put inside the parentheses instead of just the variable, then the loop will iterates the whole content of the column.
<?php
$connect_db=mysqli_connect('localhost','root','root','db');
$fetch_data="SELECT * FROM tabel";
$query_db=mysqli_query($connect_db,$fetch_data);
while($fetch_row=mysqli_fetch_assoc($query_db)){
$column_2_array=$fetch_row['column_2'];
echo($column_2_array);
}
?>
Why is it that on the second example above, after the first loop, while is iterating the subsequent rows on the selected column?
Clarifying my question further, if I take away break from the first example, then what is the difference between example 1 and 2? This is what confuses me since I thought they're identical.
To understand why this approach of looping mysqli_result works with a while loop you need to understand two things:
PHP uses type juggling. Each row returned by mysqli_fetch_assoc() will be an array. It is safe to assume that this array will never be empty, so the value will always be cast to true when used in boolean context.
mysqli_fetch_assoc() returns a single row from the result and moves an internal pointer to the next row. When pointer reaches the last row, each subsequent call will return NULL.
This while loop is equivalent to:
$fetch_row = mysqli_fetch_assoc($query_db); // save the first row in the variable. It could also be false
while($fetch_row) { // as long as $fetch_row is not false-ish
$column_2_array = $fetch_row['column_2'];
echo $column_2_array;
// fetch false or the next row
$fetch_row = mysqli_fetch_assoc($query_db)
}
Worth noting that such an approach to looping is not recommended. It is much easier to use a foreach loop. This will loop on the whole resultset one by one from the first row until the last. You can loop the same mysqli_result object multiple times.
foreach($query_db as $fetch_row) {
$column_2_array = $fetch_row['column_2'];
echo $column_2_array;
}
An even better alternative is to use fetch_all(MYSQLI_ASSOC) and store all rows in a multi-dimensional array. And as always, use PDO instead of mysqli whenever possible.
The simplest explanation is,
When you run mysqli_query() For successful SELECT, SHOW, DESCRIBE or EXPLAIN queries mysqli_query() will return a mysqli_result object which contains data from the database.
mysqli_fetch_assoc() - Fetch a result row(one row from the mysqli_result object) as an associative array at each time it called and moves the internal pointer to the next. $fetch_row is used to store that associative array containing data of single row getting from the mysqli_result object'
you can retrieve data belongs to that raw by using $fetch_row['column_name']
The while loop does the calling of mysqli_fetch_assoc() over and over. After one row is fetched, it goes to the next one and so on till it reaches the end of the object and returns NULL, which means false and breaks the while loop.
So in your first code sample,
$fetch_row=mysqli_fetch_assoc($query_db); will return and assign only one data row to $fetch_row (data type- assoc. array). Which makes the condition of the while loop true.

PHP: difference between array and variable containing an array?

In this [I-believe] famous loop condition
($row = $result->fetch()) (in which $result is a PDOStatement object) what is the type of the $row? Is it an "array" or an "array container"? Is there a difference between an array and a variable that holds an array?!
I ask this specially because if there wasn't any difference, then I should have been able to have my rows the whole in the $row variable after the loop is done, which is not the case, and I need another array to hold each row for me(the syntax is also different and I need empty brackets in front of the name of that array to add elements)
(According to my tutorial, fetch() is a method of the PDOStatement object that returns the next row of my table as an array).
Actually
$row is a run-time array variable which is re-created each time when loop (while loop) runs.So previous values will not be available. That's why you have to save it's data to another array variable which is created statically.
Is this recreation an intrinsic quality of the while loop?
Simon.B no it's not.
You can try
$row = [];
while($row[] = $result->fetch()){};
print_r($row);
and check.
Better alternative is to use fetchAll();
But why this above apporach is not used often:-
Because above approach will load the whole array again and again into Memory when loop runs and then assign array to that.
While when you are using run-time variable and doing assignment then the whole array is not loaded each time, only assignment will done.

PDO FETCH_FUNC data as assoc array

I need to get data in PHP from PDO with some transformations of data during the fly. The best variants are FETCH_CLASS mode and FETCH_FUNC mode.
but the problem of FETCH_CLASS is that each property need to go throw __set() method to get transformation or at least to check if it needs transformation. And for 40K rows with 50 columns each it takes too much time.
FETCH_FUNC seems ideal for me cause i get all the columns of the row at once, can make some transforms BUT, the only problem is that i don't have column names cause column values come into function as parameters and the only way to get them is to call func_get_args().
So generally the question is -> How can i get row data at once in some method of the class, function, using some combination of PDO FETCH modes as an assoc array, obj or some like columnName->columnValue structure? Using foreach after getting result is to long - i want to get transformed data already after calling pdo's fetchAll() method
Seems to me like you're overthinking this and are trying to be too clever. This will do just fine:
$data = [];
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
$data[] = myTransformation($row);
}
In other words, just fetch with FETCH_ASSOC, then call your function on that result.

While loop is not working properly

I am having a while loop in my function for getting the values 1 by 1 but i am getting the only 1 value
while($row= mysqli_fetch_array($this->result))
{
$image=$this->getEventDetails($row['Album_top'],'Event_image');
$alert.="<div class=facBox>
<a href='gallery.php?id=$row[Id]' style=margin-top:0px;>
<img src='admin/customer/eventgallery/$image' alt=''>
</a>
<div class=clear></div>
<a href='gallery.php?id=$row[Id]' style=margin-top:0px;>$row[Album_title]</a>
</div>";
}
I am getting the image name from another function that is
function getEventDetails($id,$fieldname)
{
$get="Select * from sarnaevent where Id='$id'";
$this->result=mysqli_query($this->con,$get);
$row=mysqli_fetch_array($this->result);
return $row[$fieldname];
}
Now i am getting the only value from the loop my $alert is having only one facbox. if i remove this line
$this->getEventDetails($row['Album_top'],'Event_image');
It works fine but i want this line to get the image name.
Inside getEventDetails(), you assign $this->result, overwriting the previous contents of $this->result. Since that occurs inside the while loop where the previous result is being used, the loop exits because there are no further results to retrieve from the inner fetch.
User a different temporary result set inside teh getEventDetails() method.
function getEventDetails($id,$fieldname)
{
$get="Select * from sarnaevent where Id='$id'";
// Different variable name...
$temporary_result = mysqli_query($this->con,$get);
$row=mysqli_fetch_array($temporary_result);
return $row[$fieldname];
}
In general, I would question the need to be storing a transient result resource into the object's $this->result for most purposes. In any case where you're using that inside a method, you are probably better off using a variable scoped only to the method, which lives only for the lifetime that result set is being used.
Please use caution when sending $id directly into the query. Although I suspect it is known to be an integer variable, and therefore it won't break the SQL, it's a good idea to get into the habit of using prepare()/execute() to prevent SQL injection.
One final point of caution: When placing the string variable into your HTML markup, be sure to use htmlspecialchars() to escape it against malforming the HTML. (If the Id is known to be an integer, it isn't necessary there)
"...<a href='gallery.php?id=$row[Id]' style=margin-top:0px;>" . htmlspecialchars($row['Album_title']) . "</a>..."
Instead of using mysqli_fetch_array() try using mysqli_fetch_assoc (see: http://php.net/manual/en/mysqli-result.fetch-assoc.php); the returned array will be associative (key-value pairs) where the keys are the column names.
You're blowing out your original query.
First, you do a query, and assign its result to $this->result. You then iterate across those results. For the first row, you immediately make a new query, overwrite $this->result with the new results, and then try to continue... but you've just replaced the rest of your results with the single result from the event details query, so mysqli_fetch_array doesn't find any more results.
Solution: use a separate variable for that result. A local one should be fine, since you don't use it outside that function. You may also need to use a separate connection; I'm not sure of that. Try it with just changing $this->result in getEventDetails() to use something like $eventResult instead.

A While Loop Condition In PHP

I have seen the following while loop condition in many examples and even I have used it in many times. I know how it works and how to use it. But as i code the condition here doesn't make any sense.
As I see the code, the condition is like it's always true. Just like while(1). Because to the *mysql_fetch_assoc()*, the same data is passed is passed all the time. So the condition is a constant.
while($arr = mysql_fetch_assoc($data))
{
//other code
}
Now, where Am I Wrong ????
Each call to mysql_fetch_assoc gets the next row from the result set. If there is no row anymore it returns false and the loop terminates.
$data is a resource data type and will probably keep the state about which row was fetched last.
This is not so unusual, even arrays have an internal pointer to the current element which can be manipulated using certain array functions.
From the PHP website, mysql_fetch_assoc "Returns an associative array of strings that corresponds to the fetched row, or FALSE if there are no more rows."
Therefore, whenever there are still rows available, mysql_fetch_assoc will return an associated array of the row contents, will increment the pointer to the next row and the while loop will execute.
When there are no more rows mysql_fetch_assoc will return FALSE and the loop will break.
Also note that as of PHP 5.5.5 this function will be deprecated.

Categories