PHP scope question - php

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.

Related

Overwrite the original array values in PHP in nested loop

Cutting out some of the code on the innermost foreach, I'm trying to change HERE to make it so that it alters the original value. I want to pass a pointer basically and alter it. I was able to kind of do this with the &$ keyword in the foreach but (as the docs state) it results in some buggy behavior and I'm trying to do it the way they, and others on SO suggest. The problem is all the examples I find are for a single foreach, not for nested.
The following code loops properly but when I get to the HERE it doesn't actually alter the original value. Also worth mentioning that $sources could be an array of arrays (by index) or an array of key values. This looping code seems to iterate over both fine though, just not overriding the original value of $sources
fwiw, on top of the &$ I also tried:
$sources[$sourceKey][$rowKey][$cellKey] = $date->format('m/d/Y');
Which $sources[$sourceKey][$rowKey][$cellKey] returns the right value if I print it but it still doesn't overwrite the original array.
function convertDates($sources) {
foreach($sources as $sourceKey => $sourceValue){
foreach ($sourceValue as $rowKey => $rowValue) {
foreach ($rowValue as $cellKey => $cellValue) {
HERE = $date->format('m/d/Y');
}
}
}
}
I never could get this to work correctly since there were two formats this loop could get (JSON encoded object and an array). Making it work for both was much harder than just doing it in JavaScript so instead of modifying on the server I format the data how I want client side and send it up. This formatting is purely presentational and for personal use so if someone were to put in a debugger and change the code to send a different format thats fine and there's no security issues.
So in the end, this code was rewritten in JS and since JS handles arrays and objects using the same pointers the above issue wasn't an issue any longer.

Insert into array during foreach

I'm fairly certain the answer is no, but is it possible to insert something into an array during a foreach loop? Ideally at the very spot you are at in the array during the loop.
For example:
foreach($stock->StockData as &$stock) {
if($dateTime < $stock['DateTime']) {
// INSERT NEW RECORD AT THIS SPOT IN THE ARRAY
}
}
As I say, I'm fairly certain the answer is no, but rather than build a new array, I just thought I'd ask.
I stand corrected!
http://docstore.mik.ua/orelly/webprog/php/ch05_07.htm
It apparently is just fine to do this in PHP.
According to the reference, PHP operates on a copy of the array when you start a foreach iterator, meaning that the iterator will not be corrupted by operations on the original array within the body of the foreach!
You really don't want to mutate an object is being iterated on. It will break your iterator/loop and could possibly crash the script/program by accessing or changing memory that you don't have access to anymore, possibly because array size has reduced.

Two foreach loops with same variable names break the order of elements

Here is my code:
foreach($datawallright['adds'] as &$ad){
$ad['img'] = get_ad_pic_url($this->em->getReference("models\MmAds",$ad['id']),'/crop_');
$ad['description'] = ucfirst(strip_tags(html_entity_decode(mb_strtolower(str_replace(array("___","---"),"",$ad['description']), "UTF-8"))));
$ad['titleurl'] = title_url($ad['title']);
}
foreach($datawallright['adds'] as $ad){
$this->load->view("view_wallpage_add",array("ad"=>$ad,"isuserwall"=>$isuserwall));
}
I have two for loops going through the same array. The variables assigned in this two for loops are the same. The weird thing is when it iterates through the second for loop. The first n-1 element are correct, but in the place of the last element the element that is one before last appeares. I can do it all in one for loop. I can change the name of the variable $ad and then it works fine, but I want to know what happened.
What happened is that the first loop iterates by reference, so when the second attempts to assign "the current item" to $ad it actually updates your array contents in addition to updating $ad.
The simplest fix is to add an unset ($ad) immediately after the first foreach so that PHP will not consider the name $ad a reference from that point onward.
The need to do this (or else suffer from hidden updates to the reference later on) is one of the ugliest things that can bite you in PHP; personally I am very religious about appending an unset after iterating by reference, even if that's the last statement in a function.

array to variables

I'm programming in PHP and I have a huge array which contains a lot of ID's. I need all these ID's to be variables so I can use these in another function. I have done a lot of research on loops in PHP but I can find one which "converts" the arrays into variables that I can use in another function. So far I have a foreach loop which processes the whole array and divided into $persons. But when I use $persons in the next function it only uses the last array. My code is as follows:
$retrieved_id_array=explode(",",$retrieved_id_string);
foreach($retrieved_id_array as $persons)
$retrieved_string=file_get_contents("https://HDXLfansite.com/$persons");
So the problem is how do I make a loop which provides me with several variables I can use in another function? Or should I use another method/code?
thats because you are overwriting your variable $retrieved_string in loop, you could do:
foreach($retrieved_id_array as $persons) {
//add it in array
$retrieved_string[] =file_get_contents("https://HDXLfansite.com/$persons");
}

Is this foreach loop responsible for god killing cats?

As taken from https://stackoverflow.com/questions/4891301/top-bad-practices-in-php
Is this similar code killing kittens, too?
foreach (file("longFile.txt") as $line) {
// ouch! Kitten killed
}
??
For those who have no idea what am I talking about:
Is PHP getting longFile.txt everytime it goes to next line of file or no? Talking about this code:
foreach (file("longFile.txt") as $line) {
// something
}
In the linked question the for loop incurs a performance hit by calling count on every iteration. foreach uses internal pointers to iterate through the array passed to it.
In your example file() will be called once and the resulting array will be passed to foreach which will iterate through it, thus the kittens are saved. Happy Caturday!
It shouldn't be killing any kittens, since, in order for PHP to get the following line of the file, it has to know the position of the file pointer since the previous line that was pulled off. You are only advancing the iterator, which maintains a reference to the file object.
Also, it's bad practice to be opening a file like that; you should have a variable to store it in and close it when you're done.
You want to use a Duff Device to unroll the loop: http://de.wikipedia.org/wiki/Duff%E2%80%99s_Device. This would be faster then foreach and faster then for loop without using count() on each iteration and it would be faster then concatenating and rtrim the string but the same like using implode().
Is that file really large? Consider:
foreach(new SplFileObject($path) as $line) {
// neither kill puppies nor kittens
}
foreach works always on the concrete iterator. If you're passing an array:
Unless the array is referenced, foreach operates on a copy of the specified array and not the array itself. (ref)
So nor array or function call will executed each time the foreach steps ahead.
Related: How to store and reset a PHP array pointer?
No. There are many reasons why kittens die, but foreach loops are not one of them.

Categories