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;
Related
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.
When working with existing code, it takes one array and places it into another in the fashion shown below.
I believe the empty brackets are the same thing as simply pushing it and appending it to the first available index.
$g['DATA'][] = $p;
After this is done, I have my own array that I would like to append to this as well. I tried using array_merge() with $g['DATA'][]as a parameter, but this is invalid for obvious reasons.
My only thought is to create a foreach loop counter so I can figure out the actual index it created, however I have to assume there is some cleaner way to do this?
Just simply use the count() of your $g["DATA"] array as index and then you can merge it like this:
$g['DATA'][count($g["DATA"])-1] = array_merge($g['DATA'][count($g["DATA"])-1], $ownArray);
//^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^
// -1 Because an array is based index 0 -> means count() - 1 = last key
Disregarding security issues (for now)
I am using json_encode to display the contents of a select query.
I used:
$sql= {query code};
// created a temp array to hold data and an array for all the results
$resultArray = array();
$tempArray = array();
// looped through every object in the result set
while ($row = $result->fetch_object());
// added it into the results array
$tempArray = $row;
array_push($resultsArray, $temparray);
// encoded the array to a json format
echo json_encode($resultArray);
Question: My objects don't have names, so it makes it difficult for me to write any code that could read the results and display them. How do I name the objects? Is it an entry I could add into the table (let's say in a case of different names I could give each object)
You should try to build the array/object structure you want in PHP. That way when you json_encode it, you'll know what it looks like and it will be what you want.
Try:
echo json_encode(array('people' => $resultArray));
In fact this should not work at all. Casting PDO (or MySQLi, as mentioned in comment) objects to JSON. You should use fetch_assoc instad, that would return associative array that could be put directly in JSON structure.
I'm new to programming and I'm tackling arrays. I thought I had multi-dimensional arrays figured out but I guess I don't. Here's the code I'm working on:
$loopcounter = 0;
while ($myrow = mysql_fetch_array($results)) {
//...other stuff happens...
$allminmax[$loopcounter][] = array("$myrow[3]","$currentcoltype","$tempmin","$tempmax");
$loopcounter++;
}
This chunk of code is supposed to create an array of four values ($myrow[3], currentcoltype, tempmin, tempmax) and insert it into another array every time the loop goes through. When I do this:
echo implode($allminmax);
I get:
ArrayArrayArrayArrayArrayArrayArrayArrayArray
Do I need to implode each array before it goes into the master array? I really want to be able to do something like $allminmax[0][4] and get the $tempmax for the first row. When I try this now nothing happens. Thanks -- any help is appreciated!
It looks like you should either use [$loopcounter] or [], but not both. You also should drop the quotes. They're unnecessary and in the case of "$myrow[3]" they interfere with the variable interpolation.
$allminmax[] = array($myrow[3], $currentcoltype, $tempmin, $tempmax);
By the way, arrays are zero-indexed, so to get $tempmax for the first row it'd be $allminmax[0][3] not $allminmax[0][4].
Also, a better way to display the contents of your array is with print_r or var_dump. These will display arrays within arrays while a simple echo will not.
var_dump($allminmax);
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.