PHP: difference between array and variable containing an array? - php

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.

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.

MySQLi fetch_all Error with Consecutive Calls

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.

PHP array_merge replacing existing array values

I'm having a problem with some PHP code fetching from a Database using PDO and I was wondering if anyone could help me on this. I've got a class which fetches events from a database and returns the result in an array.
The relevant part of the code is:
$seminars = array();
$sql = 'select * from seminars';
$stmt = $this->dbconn->query($sql);
$stmt->setFetchMode(PDO::FETCH_INTO, new SeminarEvent);
foreach($stmt as $seminar) {
echo "<p>Seminar Row: ".var_dump($seminar)."</p>"; // Prints the unique row
$seminars[] = $seminar;
echo "<p>";var_dump($seminars);echo "</p>"; // Debug
}
(SeminarEvent is a class I've written containing relevant fields with getters and setters which has been included in the header)
I've read on the docs on php.net is that $array[] = $elem and array_push($array, $elem) both add $elem to the END of the array so I've tried using both and I'm getting the same result:
The part that's an issue for me is adding $seminar to the array is replacing ALL values in the whole array. This also happens when using array_merge. The output of var_dump is showing that the array size is increasing by 1 (as expected) but the all values are all replaced with the newly inserted item each time I'm adding an item to the array. I have tried this code on another server and I get exactly the same result.
Have I missed something simple here?
EDIT:
I've added in an extra line to print out the current $seminar from the foreach loop and the output is different each time so $seminar is correctly referencing each row from the statement however the $seminars array is only containing the last item added to the array.
I think it's because SeminarEvent created once and the used by pointer, so every time the same object is populated and every time the same link saved to array. So one possible solution here is to write $seminars[] = clone $seminar; instead of $seminars[] = $seminar;

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.

PHP scope question

I'm trying to look through an array of records (staff members), in this loop, I call a function which returns another array of records (appointments for each staff member).
foreach($staffmembers as $staffmember)
{
$staffmember['appointments'] = get_staffmember_appointments_for_day($staffmember);
// print_r($staffmember['appointments'] works fine
}
This is working OK, however, later on in the script, I need to loop through the records again, this time making use of the appointment arrays, however they are unavailable.
foreach ($staffmembers as $staffmember)
{
//do some other stuff
//print_r($staffmember['appointments'] no longer does anything
}
Normally, I would perform the function from the first loop, within the second, however this loop is already nested within two others, which would cause the same sql query to be run 168 times.
Can anyone suggest a workaround?
Any advice would be greatly appreciated.
Thanks
foreach iterates over a copy of the array. If you want to change the value, you need to reference it:
foreach($staffmembers as &$staffmember) // <-- note the &
{
$staffmember['appointments'] = get_staffmember_appointments_for_day($staffmember);
// print_r($staffmember['appointments'] works fine
}
From the documentation:
Note: Unless the array is referenced, foreach operates on a copy of the specified array and not the array itself. foreach has some side effects on the array pointer. Don't rely on the array pointer during or after the foreach without resetting it.
and
As of PHP 5, you can easily modify array's elements by preceding $value with &. This will assign reference instead of copying the value.

Categories