How to break foreach loop from a XDebug session? - php

I have a foreach loop and that is doing some time consuming stuff:
$someHugeArray = [...]; // having beyond 300 to 1000 items
foreach ($someHugeArray as $item) {
$this->applyTimeConsumingMagic($item);
}
When debugging this I try to avoid iterating all of them items, so I am often writing escape code along the lines of:
foreach ($someHugeArray as $i => $item) {
$this->applyTimeConsumingMagic($item);
if ($i > 10) { break; } // #fixme: should not go live
}
And as the comment indicates, something like this did once go live making me feel like an amateur.
Is there some way to break the foreach loop from an XDebug session without writing var_dumpy code? As an IDE I use PhpStorm.

I did not find a way to break a foreach loop on the fly, yet the best next thing one can do is to decrease the array size on the fly.
Set a breakpoint after you set up your array, at best before the loop starts. (It does work inside the loop as well, yet could have weird behavior)
Select Evaluate expression phpstorm's debug window or use shortcut, default should be Alt + Shift + 8
run $someHugeArray = array_slice($someHugeArray, $offset = 0, $length = 10);
Besides array_slice one could also use array_filter if one wants to filter by more specific conditions using a closure.
Now you have a small array, enjoy fast execution time without having to worry to clean up after your debug session.

This will break the loop on the 10th run through - but obviously can be set to say 2 or 3 etc:
$myArray = $this->getHugeDataArray();
$i = 0; //here we set i to 0 so we can count to 10
foreach ($myArray as $key => $value)
{
$i++;
if ($i == 9) {break;}
//rest of actual code
}

Related

PHP ForEach - how to jump to another index

I have a php foreach loop and would like to make a condition if true to jump to the index +2.
I know about continue that will go to the next, but my goal is to go to the actual_index + 2.
This is because I have a switch case and I need to do something inside.
I know also that this is possible with the for loop by setting manually the $i, but for the foreach loop, is it possible ?
You cannot do that with foreach(). Use for() instead to control the index yourself
I think you can best use the for loop, this gives you a little bit more control over the loop.
$array = [];
for($i = 0; $i < 100; $i++) {
if ($array[$i]) $i+=2;
}
Why not change your array to a stack? Looping it with a while clause and whenever you wish to skip 1, 2 or many more just pop or shift off from the array ( pop/shift based on the direction of your initial loop ofcourse ).

Weird PHP behaviour - What's going on? [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Strange behavior Of foreach
Just came across this bug recently in a PHP app. Not sure what's going on.
Basically, it shows up when using a combination of two foreach (one with &, one without).
Here's a test code that reproduce the problem:
$items = array(
array('id'=>1, 'name'=>'foo', 'value'=>150),
array('id'=>2, 'name'=>'bar', 'value'=>190)
);
foreach($items as &$item)
{
$item['percentage'] = $item['value'] * 0.75;
}
var_dump($items); // All Good
foreach($items as $item)
{
var_dump($item); // Shows 1st item twice
}
The second foreach loop runs the block twice, as expected, but $item remains stuck on the first item.
I understand this is likely caused by the use of the reference & in the first loop but I don't see why it should behave like this..
Any idea? is that a bug?
Getting the same result on 5.3.8, 5.3.10 & 5.4
Firstly, it is not a bug as Rasmus said. See https://bugs.php.net/bug.php?id=29992
In this, right implementation of modifying array with its loop variable with &.
<?php
$arr = array(1, 2, 3, 4);
foreach ($arr as &$value) {
$value = $value * 2;
}
// $arr is now array(2, 4, 6, 8)
unset($value); // break the reference with the last element
var_dump($arr); // All Good
foreach($arr as $value) {
var_dump($value); // All good
}
?>
This is odd PHP behavior that's been around pretty much forever, and it happens when you mix the use of a variable as reference then not reference like you did.
I deal with it with a naming convention as follows: When I am using foreach with a &$item, I name it like &$refItem. This keeps me from mixing types.
You need to unset the pointer after using foreach with a referenced array.
http://php.net/unset
This may be something that look more understand the problem of foreach
$last_value_of_first_foreach = 1;
$item = 2;
$c = 3;
$item = &$last_value_of_first_foreach ; // Think that this statement is first foreach loop
// Here $item is pointer to $last_value_of_first_foreach
// To Better understanding, let change the name ($reference_to_last_value = $item;)
now, the new loop is
$item = $c;
// Here, what it do is update value where the $item pointer refer to
// (mean $last_value_of_first_foreach )
// so, at here $last_value_of_first_foreach has value of $c
Now, back to your case, from the first foreach, the $item reference to the last element of array. now, when you assign something to $item in second foreach, what it do, is put something inside that one.
In the end of first loop
$item is pointer to $items[1]
The first of second loop
it will push the first element to the location where the $item point to (that mean $items[1], so that why $items[1] is replaced by $items[0].
In case you want to prevent this one, just unset the $item variable before next time usage.
This is a normal, not a weird behavior. Just read about reference here.
When you add & in front of a variable, you store the reference to a variable. So, when you re-use it, it will also change the contents of the referenced variable.
foreach($items as &$item) // You have $item here, prefixed with &.
{
$item['percentage'] = $item['value'] * 0.75;
}
var_dump($items);
foreach($items as $item) // And your re-use it here.
{
var_dump($item);
}
To solve this, add unset($item) in the 1st loop:
foreach($items as &$item)
{
$item['percentage'] = $item['value'] * 0.75;
unset($item); // add this, because you use &$item previously.
}

Change the auto increment amout in a foreach loop

Is there a way to make a foreach loop increment by more than one? I am loading a jquery script before each item in a foreach loop and I want the delay to increase by 300 for each item, so that each item animates separately as opposed to at the same time.
So is there another method other than $i++? Like $i++ + 300? Or I am reaching a little too far on this one?
Thanks everyone for responding so quickly. The $i+=300 was exactly what I was looking for. I used this variable to increase the delay time on each of the scripts so it is executed one at a time on each item in the loop. Here is a link to what I used it for. Thanks again!
http://cloudninelabs.com/c9v10/portfolio/
Basically you need to look after the counter yourself.
For example:
$i = 0;
foreach( $somelist as $index => $content ) {
// Do something with $content using $i
$i += 300;
}
Are you looking for something like this:
foreach (array(1, 2, 3, 4) as &$value) {
$value = $value + 300;
}
Your question is kinda unclear to me, but it seems like you can simply use i*300 as your animation interval (e.g. foreach ($foo as $i => $bar) { /*simply use $i*300 as your interval here*/ })
However, just FIY, n a regular for loop you can use $i+=300 (e.g. for ($i=0; $i<10000; $i+=300). It doesn't make much sense to do anything like that in an foreach loop. Instead, keep a separate variable to keep track of that and increase that be 300 every time ($i=0; foreach ($foo as $bar) { ... $i+=300 }).

How can I find out how many times a foreach construct loops in PHP, without using a "counter" variable?

If I have a foreach construct, like this one:
foreach ($items as $item) {
echo $item . "<br />";
}
I know I can keep track of how many times the construct loops by using a counter variable, like this:
$counter = 0;
$foreach ($items as $item) {
echo $item.' is item #'.$counter. "<br />";
$counter++;
}
But is it possible to do the above without using a "counter" variable?
That is, is it possible to know the iteration count within the foreach loop, without needing a "counter" variable?
Note: I'm totally okay with using counters in my loops, but I'm just curious to see if there is a provision for this built directly into PHP... It's like the awesome foreach construct that simplified certain operations which are clunkier when doing the same thing using a for construct.
No it's not possible unless your $items is an array having contiguous indexes (keys) starting with the 0 key.
If it have contiguous indexes do:
foreach ($items as $k => $v)
{
echo $k, ' = ', $v, '<br />', PHP_EOL;
}
But as others have stated, there is nothing wrong using a counter variable.
There's no easier way - that's kinda what count variables are for.
I'm assuming that you want to know the current count during the loop. If you just need to know it after, use count($items) as others have suggested.
You could tell how many time it WILL loop or SHOULD have looped by doing a
$loops = count($items);
However that will only work if your code does not skip an iteration in any way.
foreach loops N times, where N is just the size of the array. So you can use count($items) to know it.
EDIT
Of course, as noticed by Bulk, your loop should not break (or maybe continue, but I would count a continue as a loop, though shorter...)

What's quicker, an array lookup (including array build) or an IF stack?

I was wondering which was better:
$lookup = array( "a" => 1, "b" => 2, "c" => 3 );
return $lookup[$key];
or
if ( $key == "a" ) return 1
else if ( $key == "b" ) return 2
else if ( $key == "c" ) return 3
or maybe just a nice switch...
switch($key){
case "a": return 1;
case "b": return 2;
case "c": return 3;
}
I always prefer the first method as I can separate the data from the code; At this scale it looks quite silly but on a larger scale with thousands of lines of lookup entries; How much longer is PHP going to take building an array and then only checking maybe 1 or 2 entries per request.
I think it'd have to be tested and clocked, but I'd say the bigger and more complicated the array the slower it's going to become.
PHP Should be able to handle lookups faster than I can in PHP-code, but building the array in the first place surely takes up a lot of time.
For anything with measurable performance (not only 3 entries) lookup is fastest way. That's what hash tables are for.
First, it's easy to test it yourself.
Second, and more importantly, which is most appropriate for the code you're using? The amount of time you'll save is negligible in any case.
There will be a tipping point you will just have to test to find it. My guess is with 3 items you are better off with if/then/else. This is a nice article on bit counting which compared computing the number of bits and using lookups. Spoiler: Lookups won!
Are you building the array every time, or can you build it once and cache it?
If you are building it every time, I cannot see how that could be faster. Building the array by itself should take longer that the chained if()s (Adding one item to the array would be close in time to one if(), but you'd have to add every item, when you could exit from the if() early)
If you can use a cached array, than I think that would be the clear winner.
So I did a bit of testing with this example and got the following results:
emptyfunction: 0.00000087601416110992430969503855231472755349386716
lookuparray: 0.00000136602194309234629100648257538086483009465155
makearrayonly: 0.00000156002373695373539708814922266633118397294311
makearray: 0.00000174602739810943597796187489595842734502184612
ifblock: 0.00000127001986503601083772739543942265072473674081
switchblock: 0.00000131001937389373773757957151314679222764425504
Each was inside a method, so I also included the time for an empty method. They were ran 1,000,000 times each and then averaged out.
Just doing a lookup (without the building of the array) is actually slower than an if block (uses a global lookup the same as my code) and just by a fraction slower than a switch block.
I can't be bothered scaling this up to hundreds of if statements but it just shows that the if statement is faster even at this level against a single lookup.
If you've got thousands of entries, an array lookup will win hands down. The associative array might be a bit slow, but finding an array key is much faster than doing thousands of if() blocks (not to mention the time it takes to type it all out!)
You could test how long it takes to see if the value is not there as well. My guess is the array key lookup will be faster. And if you have to query it twice or more, caching the array should make it faster.
But speed is not the most important thing here. The array key is better for the long term, where you want to add and remove data. You can also get the data from another source in the future.
If you just want to look up a value
you use an array.
If you want to take an action then
if and switch both have their uses.
This is a little test for array manipulations
{
$x = 0;
foreach ($test as $k => $v) {
$x = sprintf(” % s=>%sn”,$k,$v);}
}
{
$x = 0;
reset($test);
while (list($k, $v) = each($test)) {
$x = sprintf(” % s=>%sn”,$k,$v);
}
}
{
$x = 0;
$k = array_keys($test);
$co = sizeof($k);
for ($it = 0; $it < $co; $it++) {
$x = sprintf(” % s=>%sn”,$k[$it],$test[$k[$it]]);
}
}
{
$x = 0;
reset($test);
while ($k = key($test)) {
$x = sprintf(” % s=>%sn”,$k,current($test)); next($test);
}
}
access time (ms)
8.1222
10.3221
9.7921
8.9711

Categories