If I need to change a function parameter, I can use foo(&$x) and the function can modify it.
I need something like this in a foreach loop,
$x=array(1,2,3);
foreach($x as &$i) $i=1;
var_dump($x);
results with some strange "&int(1)"...
array(3) {
[0]=>
int(1)
[1]=>
int(1)
[2]=>
&int(1)
}
But, of course, this is not the syntax (for what I whant)... It is possible to do this with PHP?
It is not "so elegant" to use for (now it works!),
$x=array(1,2,3);
for($i=0; $i<count($x); $i++) $x[$i]=1;
var_dump($x);
First off, this isn't technically a pointer. It is a reference. Before using them in your code, I'd suggest you get familiar with how they work in PHP by reading the manual section that explains them.
In this case, your code is actually correct, as documented in the manual page for foreach. foreach($x as &$i) is precisely the way to do this. Your confusion apparently comes from the output of var_dump:
&int(1)
This is precisely what you should expect. The & signifies that another variable is a reference pointing to this value. This is because $i continues to be a reference to the last element in the array even after the loop is over. This is potentially dangerous, because code elsewhere in your file may modify $i and therefore your array without you wanting it to.
It is probably good practice to unset $i after the loop is over to avoid this.
When a loop ends, the iterator still holds the last value used. In this case, the last item in the array. So it's still referenced. It doesn't really matter unless you try to reuse $i later, in which case you may get some weird results.
It would be safer to do something like this:
foreach($x as $k=>$v) {
$x[$k] = 1;
}
My homework affter good comments and answer at the comments.
Read the guide
As #lonesomeday says, "that is precisely the right syntax". The PHP guide shows that
$arr = array(1, 2, 3, 4);
foreach ($arr as &$value)
$value = $value * 2;
unset($value); // break the reference with the last element
and, as #Wrikken say, needs the unset.
Use "intermediate elegance" when you are not sure
As #MarcB20 says, take care..."foreach($x as &$i) $i=1; is VERY dangerous. $i will REMAIN a reference for the duration of your code (or until you unset it), and you can unwittingly modify the contents of the array by reusing the variable in some other context down the road"...
So, you can use an "intermediate elegance" syntax,
foreach ($arr as $key=>$value) {
// ... use $value ...
$arr[$key] = $anothervalue;
}
prefer to use simple for (with array_keys if an array associative) if the $value not used.
Related
So I have this slightly annoying issue: say I have a foreach loop like this:
foreach ($arr as $key=>$value) {
do_something($key);
}
In my eclipse environment, I have turned on the feature that displays warnings for unused variables, which is really helpful. However, it complains for all such occurences, where the $value is not used in the loop.
I was wondering if there is some syntax where I don't use this, like is available for list() :
list(,,$my_var) = some_func();
//these returns an array with 3 elements, but I only need the last one
Note: The obvious would be to use array_keys(), but I don't want a function call; I'm merely asking if there's a shorthand I don't know of, or something like it. This is why the question PHP foreach that returns keys only does not cover what I'm asking.
TBH, I couldn't find any resource to back this answer, it works fine as far as my tests went, BUT I CAN'T SAY FOR SURE WHETHER THIS IS OR ISN'T RECOMMENDED TO USE. (Probably not)
Here is what I came up with:
$arr = array('kN1' => '50', 'kN2' => 400);
//$arr = array('50', 400);
foreach ($arr as $var => $var) { // use same variable for both key and value
print_r($var);
echo '<br>';
}
// kN1
// kN2
Run Viper
To get rid of the warning without introducing too much overhead just unset the unused variable once the loop is done.
foreach ($arr as $key => &$val) {
print_r($key);
}
unset($val);
BTW: I believe one should use a reference to the unused variable (&$val instead of $val). Otherwise you might end up producing a full copy of the variable with each iteration and that might be a costly operation.
I have created a php class that implements the Iterator interface. I am successfully able to iterate through the class like this:
foreach($data as $key=>$value)
echo $key;
This, however, consistently gives me a strange result:
foreach($data as $item)
echo key($item)
The first style calls the key() method in my class for every element. The latter never calls it.
Am I missing something? That should work, shouldn't it?
Update: I think I am missing something. The key function doesn't work as I would expect it to for a simple array, either:
$test = [['name'=>'foo'],['name'=>'bar'],['name'=>'fizz']];
foreach($test as $key=>$item)
echo $key;
foreach ($test as $item)
echo key($item);
gives me 012namenamename... not quite what I was expecting. I think I need to just use the $key=>value notation, and never count on key() in a loop.
Your first version is correct, which is why it works. For a short explanation of why your second method doesn't work, see this comment in the manual.
This is because (from the manual for foreach() )
On each iteration, the value of the current element is assigned to $value and the internal array pointer is advanced by one
So your second method is fetching the next key, not the current one.
I would like to take an array and clear all of its values while maintaining its keys. By "clear" I mean replace with an empty type value, such as '' or null. PHP obviously has quite a few array functions, but I didn't find anything there that does exactly this. I am currently doing it this way:
foreach ($array as &$value) $value = ''
My question is, is there some built-in php function I overlooked, or any other way I can accomplish this without iterating over the array at this level?
Without knowing exactly what your memory/performance/object-management needs are, it's hard to say what's best. Here are some "I just want something short" alternatives:
$array = array_fill_keys(array_keys($a),""); // Simple, right?
$array = array_map(function(){return "";},$a); // More flexible but easier to typo
If you have an array that's being passed around by reference and really want to wipe it, direct iteration is probably your best bet.
foreach($a as $k => $v){
$a[$k] = "";
}
Iteration with references:
/* This variation is a little more dangerous, because $v will linger around
* and can cause bizarre bugs if you reuse the same variable name later on,
* so make sure you unset() it when you're done.
*/
foreach($a as $k => &$v){
$v = "";
}
unset($v);
If you have a performance need, I suggest you benchmark these yourself with appropriately-sized arrays and PHP versions.
Easiest way is array_map
$array = array_map(function($x) { return '';}, $array);
You can use array_keys to get the keys. You can then use array_flip if you like, although this will assign the values 0 through length-1 to the keys.
There is no single built-in function for this. You might try:
array_combine(array_keys($array),array_fill(0,count($array)-1,""));
But really the code you have right now does the job just fine.
I'm studying PHP for an advanced exam. The practice test said that the first iteration is better than the second. I not figure out why. They both iterate the contents of an array just fine.
// First one:
foreach($array as $key => &$val) { /* ... */ }
// Second one:
foreach($array as $key => $val) { /* ... */ }
The practice test said that the first iteration is better than the second.
That isn't the best advice. They're different tools for different jobs.
The & means to treat the variable by reference as opposed to a copy.
When you have a variable reference, it is similar to a pointer in C. Accessing the variable lets you access the memory location of the original variable, allowing you to modify its value through a different identifier.
// Some variable.
$a = 42;
// A reference to $a.
// & operator returns a reference.
$ref = &$a;
// Assignment of $ref.
$ref = "fourty-two";
// $a itself has changed, through
// the reference $ref.
var_dump($a); // "fourty-two"
Reference example on CodePad.
The normal behaviour of foreach is to make a copy available to the associated block. This means you are free to reassign it, and it won't affect the array member (this won't be the case for variables which are always references, such as class instances).
Copy example on CodePad.
Class instance example on CodePad.
Using a reference in a foreach has some side effects, such as a dangling $val reference to the last value iterated over, which can be modified later by accident and affect the array.
Dangling reference example on CodePad.
The first example includes the & reference-operator for $val --> any changes to $val will be saved to $array.
This is by no means "better" than example #2, though.
It's about PHP but I've no doubt many of the same comments will apply to other languages.
Simply put, what are the differences in the different types of loop for PHP? Is one faster/better than the others or should I simply put in the most readable loop?
for ($i = 0; $i < 10; $i++)
{
# code...
}
foreach ($array as $index => $value)
{
# code...
}
do
{
# code...
}
while ($flag == false);
For loop and While loops are entry condition loops. They evaluate condition first, so the statement block associated with the loop won't run even once if the condition fails to meet
The statements inside this for loop block will run 10 times, the value of $i will be 0 to 9;
for ($i = 0; $i < 10; $i++)
{
# code...
}
Same thing done with while loop:
$i = 0;
while ($i < 10)
{
# code...
$i++
}
Do-while loop is exit-condition loop. It's guaranteed to execute once, then it will evaluate condition before repeating the block
do
{
# code...
}
while ($flag == false);
foreach is used to access array elements from start to end. At the beginning of foreach loop, the internal pointer of the array is set to the first element of the array, in next step it is set to the 2nd element of the array and so on till the array ends. In the loop block The value of current array item is available as $value and the key of current item is available as $index.
foreach ($array as $index => $value)
{
# code...
}
You could do the same thing with while loop, like this
while (current($array))
{
$index = key($array); // to get key of the current element
$value = $array[$index]; // to get value of current element
# code ...
next($array); // advance the internal array pointer of $array
}
And lastly: The PHP Manual is your friend :)
This is CS101, but since no one else has mentioned it, while loops evaluate their condition before the code block, and do-while evaluates after the code block, so do-while loops are always guaranteed to run their code block at least once, regardless of the condition.
PHP Benchmarks
#brendan:
The article you cited is seriously outdated and the information is just plain wrong. Especially the last point (use for instead of foreach) is misleading and the justification offered in the article no longer applies to modern versions of .NET.
While it's true that the IEnumerator uses virtual calls, these can actually be inlined by a modern compiler. Furthermore, .NET now knows generics and strongly typed enumerators.
There are a lot of performance tests out there that prove conclusively that for is generally no faster than foreach. Here's an example.
I use the first loop when iterating over a conventional (indexed?) array and the foreach loop when dealing with an associative array. It just seems natural and helps the code flow and be more readable, in my opinion. As for do...while loops, I use those when I have to do more than just flip through an array.
I'm not sure of any performance benefits, though.
Performance is not significantly better in either case. While is useful for more complex tasks than iterating, but for and while are functionally equivalent.
Foreach is nice, but has one important caveat: you can't modify the enumerable you're iterating. So no removing, adding or replacing entries to/in it. Modifying entries (like changing their properties) is OK, of course.
With a foreach loop, a copy of the original array is made in memory to use inside. You shouldn't use them on large structures; a simple for loop is a better choice. You can use a while loop more efficiently on a large non-numerically indexed structure like this:
while(list($key, $value) = each($array)) {
But that approach is particularly ugly for a simple small structure.
while loops are better suited for looping through streams, or as in the following example that you see very frequently in PHP:
while ($row = mysql_fetch_array($result)) {
Almost all of the time the different loops are interchangeable, and it will come down to either a) efficiency, or b) clarity.
If you know the efficiency trade-offs of the different types of loops, then yes, to answer your original question: use the one that looks the most clean.
Each looping construct serves a different purpose.
for - This is used to loop for a specific number of iterations.
foreach - This is used to loop through all of the values in a collection.
while - This is used to loop until you meet a condition.
Of the three, "while" will most likely provide the best performance in most situations. Of course, if you do something like the following, you are basically rewriting the "for" loop (which in c# is slightly more performant).
$count = 0;
do
{
...
$count++;
}
while ($count < 10);
They all have different basic purposes, but they can also be used in somewhat the same way. It completely depends on the specific problem that you are trying to solve.
With a foreach loop, a copy of the original array is made in memory to use inside.
Foreach is nice, but has one important caveat: you can't modify the enumerable you're iterating.
Both of those won't be a problem if you pass by reference instead of value:
foreach ($array as &$value) {
I think this has been allowed since PHP 5.
When accessing the elements of an array, for clarity I would use a foreach whenever possible, and only use a for if you need the actual index values (for example, the same index in multiple arrays). This also minimizes the chance for typo mistakes since for loops make this all too easy. In general, PHP might not be the place be worrying too much about performance. And last but not least, for and foreach have (or should have; I'm not a PHP-er) the same Big-O time (O(n)) so you are looking possibly at a small amount more of memory usage or a slight constant or linear hit in time.
In regards to performance, a foreach is more consuming than a for
http://forums.asp.net/p/1041090/1457897.aspx