Reputation: 177
I'm stuck trying to append new data to an stdClass object that I'm creating for an AMchart
I'm returning all the rows I want from the DB, then creating a new object and looping through the returned array, but rather than appending what I want to the end of the existing object, it just gets overwritten. PHP objects dont have an append or push method, so how do you accomplish this?
Here's what my code looks like. Am I missing something simple?
$sql = 'SELECT
count(*) as clients,
STR_TO_DATE(Appt_date, \'%m/%d/%Y\') AS date,
SUM(wait_time) as total_wait_time
FROM tb_by_client
WHERE status = @qualifier
GROUP BY Appt_date';
$rows = $db->fetchAll($sql);
$chartObject = new stdClass();
foreach($rows as $row){
$row->average = round($row->total_wait_time / $row->clients);
$chartObject->date = $row->date;
$chartObject->average = $row->average;
}
$chartArray[] = $chartObject;
return json_encode($chartArray);
So instead of getting something that looks like this
[{"date":"2018-10-01","average":12},{"date":"2018-10-02","average":-33},{"date":"2018-10-04","average":23},{"date":"2018-10-05","average":6}]
I get back just a single
[{"date":"2018-10-01","average":12}]
Because each loop overwrites the last key and value
How do you append instead?
Upvotes: 0
Views: 2198
Reputation: 21661
Your problem is you overwrite the data without saving it
$chartObject = new stdClass();
foreach($rows as $row){
$row->average = round($row->total_wait_time / $row->clients);
$chartObject->date = $row->date;
$chartObject->average = $row->average;
}
$chartArray[] = $chartObject;
See on each iteration of foreach($rows as $row){
you change the data in $chartObject
, but you never save in your $chartArray
.
Do this instead
foreach($rows as $row){
$chartObject = new stdClass(); //new instance of stdClass, obj pass by refrence
$row->average = round($row->total_wait_time / $row->clients);
$chartObject->date = $row->date;
$chartObject->average = $row->average;
$chartArray[] = $chartObject;
}
Personally I wouldn't even bother with using an object:
foreach($rows as $row){
$average = round($row->total_wait_time / $row->clients);
$chartArray[] = ['date'=>$row->date,'average'=>$average];
}
When you JSON Encode an array with string keys, it will make it the correct Javascript Object structure. So there really is no need to keep all those objects in memory and the code is much smaller, cleaner, and easier to read.
One last thing I hinted at in the code, is that objects are pass by reference in PHP (now), and if you don't create a new instance of the object for each iteration, you will actually update all references to the object. This can be illustrated like this:
$obj = new stdClass;
$objects = [];
for($i=0;$i<3;++$i){
$obj->foo = $i;
$objects[] = $obj;
print_r($objects);
}
Output:
Array
(
[0] => stdClass Object
(
[foo] => 0
)
)
Array
(
[0] => stdClass Object
(
[foo] => 1
)
[1] => stdClass Object
(
[foo] => 1
)
)
Array
(
[0] => stdClass Object
(
[foo] => 2
)
[1] => stdClass Object
(
[foo] => 2
)
[2] => stdClass Object
(
[foo] => 2
)
)
Each array is a single iteration of the for
loop, this is the same array with another row added after each iteration.
As you can see each copy (its not really a copy) is updated by reference in the array. Basically we have stored the same object (instance ,will call him Bob
) 3 times, instead of 3 separate objects (Bob
, Alice
, John
).
If the data you stored was the color of a persons shirt, when Bob
puts on a red shirt, he has a red shirt on, but Alice
and John
don't.
Because of this you need to create a new instance of the object for each iteration and store that.
Hope that helps!
Upvotes: 5
Reputation: 57121
You can do the maths in the SQL and it cuts out the loop altogether...
$sql = 'SELECT STR_TO_DATE(Appt_date, \'%m/%d/%Y\') AS date,
round(SUM(wait_time)/count(*)) as average
FROM tb_by_client
WHERE status = @qualifier
GROUP BY Appt_date';
return json_encode($db->fetchAll($sql));
Upvotes: 3
Reputation: 499
You're misunderstanding what should be in the loop and what shouldn't.
This should be fine:
$sql = 'SELECT
count(*) as clients,
STR_TO_DATE(Appt_date, \'%m/%d/%Y\') AS date,
SUM(wait_time) as total_wait_time
FROM tb_by_client
WHERE status = @qualifier
GROUP BY Appt_date';
$rows = $db->fetchAll($sql);
$chartArray = [];
foreach($rows as $row){
$row->average = round($row->total_wait_time / $row->clients);
$chartObject = new stdClass();
$chartObject->date = $row->date;
$chartObject->average = $row->average;
$chartArray[] = $chartObject;
}
return json_encode($chartArray);
Upvotes: 1