This may sound weird but since not an English native, I'm having a trouble grasping the semantics of 'as' in the code.
$array = array(1, 2, 3, 4);{
foreach ($array as &$value)
$value = $value * 2;}
I don't get the meaning of as. I get what the command line is producing, but it's confusing for me probably as some of this would be for you:
foreach ($array with &$value)
or
foreach ($array then &$value)
Can some native Englishman/lady explain me why was 'as' chosen for this purpose.
It means something like
foreach item in $array provide it to me as variable $value
Just look it up in the wiktionary:
In the manner or role specified.
The kidnappers released him as agreed. The parties were seen as agreeing on a range of issues. He was never seen as the boss, but rather as a friend.
So in the context of foreach it means: go through every element of the array and use it as the specified variable (foreach($array as $content)).
For example, if there are 3 items in $array with numeric index, then the as means each time through the loop $value equals the current item, so you can think of it as an alias for the current item:
//first iteration
$value = $array[0]
//second
$value = $array[1]
//third
$value = $array[2]
It is the same as:
for($key=0; $key<count($array); $key++) {
$value = $array[$key];
}
foreach($array as $key => $value) { }
Related
I'm trying to find a simpler way to create new arrays from existing arrays and values. There are two routines I'd like to optimize that are similar in construction. The form of the first one is:
$i = 0;
$new_array = array();
foreach ($my_array as $value) {
$new_array[$i][0] = $constant; // defined previously and unchanging
$new_array[$i][1] = $value; // different for each index of $my_array
$i++;
}
The form of the second one has not one but two different values per constant; notice that $value comes before $key in the indexing:
$i = 0;
$new_array = array();
foreach ($my_array as $key => $value) {
$new_array[$i][0] = $constant; // defined previously and unchanging
$new_array[$i][1] = $value; // different for each index of $my_array
$new_array[$i][2] = $key; // different for each index of $my_array
$i++;
}
Is there a way to optimize these procedures with shorter and more efficient routines using the array operators of PHP? (There are many, of course, and I can't find one that seems to fit the bill.)
I believe a combination of Wouter Thielen's suggestions regarding the other solutions actually holds the best answer for me.
For the first case I provided:
$new_array = array();
// $my_array is numeric, so $key will be index count:
foreach ($my_array as $key => $value) {
$new_array[$key] = array($constant, $value);
};
For the second case I provided:
// $my_array is associative, so $key will initially be a text index (or similar):
$new_array = array();
foreach ($my_array as $key => $value) {
$new_array[$key] = array($constant, $value, $key);
};
// This converts the indexes to consecutive integers starting with 0:
$new_array = array_values($new_array);
it is shorter, when you use the array-key instead of the $i-counter
$new_array = array();
foreach ($my_array as $key => $value) {
$new_array[$key][0] = $constant; // defined previously and unchanging
$new_array[$key][1] = $value; // different for each index of $my_array
}
Use array_map:
$new_array = array_map(function($v) use ($constant) {
return array($constant, $v);
}, $my_array);
If you want to use the keys too, for your second case:
$new_array = array_map(function($k, $v) use ($constant) {
return array($constant, $v, $k);
}, array_keys($my_array), $my_array);
Assuming the $constant variable is defined in the caller's scope, you'll need to use use ($constant) to pass it into the function's scope.
array_walk is similar, but modifies the array you pass to it, so if you want to update $my_array itself, use array_walk. Your second case then becomes this:
array_walk($my_array, function(&$val, $key) use($constant) {
$val = array($constant, $val, $key);
});
In both examples above for the second case, you'll end up with an associative array (i.e. with the keys still being the keys for the array). If you want to convert this into a numerically indexed array, use array_values:
$numerically_indexed = array_values($associative);
I asked a question similar to this a few days ago, check it out:
PHP - Fastest way to convert a 2d array into a 3d array that is grouped by a specific value
I think that you have an optimal way when it comes to dealing with large amount of data. For smaller amounts there is a better way as was suggested by the benchmarks in my question.
I think too that readability and understanding the code can also be an issue here and I find that things that you can understand are worth more later on than ideas that you do not really grasp as it generally takes a long time to understand them again as it can be quite confusing while debugging issues.
I would suggest, you take a look at the differences between JSON encoded arrays and serialised arrays as there can be major performance differences when working with the two. It seems that as it is now JSON encoded arrays are a more optimised format (faster) for holding and working with data however this will likely change with PHP 7. It would be useful to note that they are also more portable.
Further Reading:
Preferred method to store PHP arrays (json_encode vs serialize)
http://techblog.procurios.nl/k/n618/news/view/34972/14863/cache-a-large-array-json-serialize-or-var_export.html
Why is an empty foreach loop can change the result.
I have the following code:
$variable = [1,2,3,4];
foreach ($variable as $key => &$value)
$value ++;
var_dump($variable);
The result I get is:
array (size=4)
0 => int 2
1 => int 3
2 => int 4
3 => &int 5
Now, when I add an empty foreach loop like this:
$variable = [1,2,3,4];
foreach ($variable as $key => &$value)
$value ++;
foreach ($variable as $key => $value);
var_dump($variable);
I get this :
array (size=4)
0 => int 2
1 => int 3
2 => int 4
3 => &int 4
can someone explain me why the last element doesn't change when I add the second empty loop, and why there is a & infront of the last element?
At the end of the first loop, $value is pointing to the same place as $variable[3] (they are pointing to the same location in memory):
$variable = [1,2,3,4];
foreach ($variable as $key => &$value)
$value ++;
Even as this loop is finished, $value is still a reference that's pointing to the same location in memory as $variable[3], so each time you store a value in $value, this also overwrites the value stored for $variable[3]:
foreach ($variable as $key => $value);
var_dump($variable);
With each evaluation of this foreach, both $value and $variable[3] are becoming equal to the value of the iterable item in $variable.
So in the 3rd iteration of the second loop, $value and $variable[3] become equal to 4 by reference, then during the 4th and final iteration of the second loop, nothing changes because you're passing the value of $variable[3] (which is still &$value) to $value (which is still &$value).
It's very confusing, but it's not even slightly idiosyncratic; it's the code executing exactly as it should.
More info here: PHP: Passing by Reference
To prevent this behavior it is sufficient to add an unset($value); statement after each loop where it is used. An alternative to the unset may be to enclose the foreach loop in a self calling closure, in order to force $value to be local, but the amount of additional characters needed to do that is bigger than just unsetting it:
(function($variable){
foreach ($variable as $key => &$value) $value++;
})($variable);
This is a name collision: the name $value introduced in the first loop exists after it and is used in the second loop. So all assignments to it are in fact assignments to the original array. What you did is easier observed in this code:
$variable = [1,2,3,4];
foreach ($variable as $key => &$value)
$value ++;
$value = 123; // <= here you alter the array!
var_dump($variable);
and you will see $variable[3] as 123.
One way to avoid this is, as others said, to unset ($value) after the loop, which should be a good practice as recommended by the manual. Another way is to use another variable in the second loop:
$variable = [1,2,3,4];
foreach ($variable as $key => &$value)
$value ++;
foreach ($variable as $key => $val);
var_dump($variable);
which does not alter your array.
The last element of the array will remian even after the foreach loop ..So its needed to use unset function outside the loop ..That is
$variable = [1,2,3,4];
foreach ($variable as $key => &$value) {
$value++;
}
unset($value);
var_dump($variable);
The link to the manual can be found here http://php.net/manual/en/control-structures.foreach.php
As phil stated in the comments:
As mentioned in the manual, you should unset() references after use.
$variable = [1,2,3,4];
foreach ($variable as $key => &$value) {
$value ++;
}
unset($value);
foreach ($variable as $key => $value);
print_r($variable);
Will return:
Array
(
[0] => 2
[1] => 3
[2] => 4
[3] => 5
)
Example
Explanation
Taken from the foreach() manual. (See the big red box)
Reference of a $value and the last array element remain even after the
foreach loop. It is recommended to destroy it by unset().
It basically means: That the referenced value &$value and the last element/item in the array, which in this case is 4 remain the same. To counter-act this issue, you'll have to unset() the value after use, otherwise it will stay in the array as its original value (if that makes sense).
You should also read this: How does PHP 'foreach' actually work?
After loop you should unset this reference using:
unset($value);
So your whole code should work like this:
$variable = [1,2,3,4];
foreach ($variable as $key => &$value) {
$value++;
}
unset($value);
var_dump($variable);
There is no point to put unset($value); inside the loop
Explanation - after loop $value is still set to the last element of array so you can use after your loop $value = 10; (before unset) and you will see that last element of array has been changed to 10. It seems that var_dump want to help us a bit in this case and shows there is reference for last element and of course when we use unset we have desired output of var_dump.
You could also look at the following script:
<?php
$array = [1, 2, 3, 4];
var_dump($array);
$x = &$array[2];
var_dump($array);
$x += 20;
unset($x);
var_dump($array);
?>
We don't use loop here and if reference is set to element of array, var_dump shows us this putting & before type of this element.
However if the above code we changed reference and set it this way $x = &$array; var_dump wouldn't show us any reference.
Also in the following code:
<?php
$x = 23;
$ref = &$x;
var_dump($x);
?>
var_dump() won't give us any hint.
Obligatory statement: References are evil!
Stepping through your code:
$variable = [1,2,3,4];
foreach ($variable as $key => &$value)
$value++;
After the loop completes; $value is a reference to $variable[3] and thus has the value of int(4).
foreach ($variable as $key => $value);
At each iteration, $variable[3] gets assigned an element of $variable[<k>] where 0 <= k < 3. At the last iteration it gets assigned to its own value which is that of the previous iteration, so it's int(4).
Unsetting $value in between the two loops resolves the situation. See also an earlier answer by me.
for example:
$numbers = array(1, 2, 3, 4, 5);
foreach($numbers as $value)
{
echo $value;
}
what does as do, I assume it's a keyword because it is highlighted as one in my text editor. I checked the keyword list at http://www.php.net/manual/en/reserved.keywords.php and the as keyword was present. It linked to the foreach construct page, and from what I could tell didn't describe what the as keyword did. Does this as keyword have other uses or is it just used in the foreach construct?
It's used to iterate over Iterators, e.g. arrays. It reads:
foreach value in $numbers, assign the value to $value.
You can also do:
foreach ($numbers as $index => $value) {
}
Which reads:
foreach value in $numbers, assign the index/key to $index and the value to $value.
To demonstrate the full syntax, lets say we have the following:
$array = array(
0 => 'hello',
1 => 'world')
);
For the first iteration of our foreach loop, $index would be 0 and $value would be 'hello'. For the second iteration of our foreach loop, $index would be 1, and $value would be 'world'.
Foreach loops are very common. You may have seen them as for..in loops in other languages.
For the as keyword, you're saying:
for each value in $numbers AS $value
It's a bit awkward, I know. As far as I know, the as keyword is only used with foreach loops.
as is just part of the foreach syntax, it's used to specify the variables that are assigned during the iteration. I don't think it's used in any other context in PHP.
I am looking for a Perl equivalent to the following php code:-
foreach($array as $key => $value){
...
}
I know I can do a foreach loop like so:-
foreach my $array_value (#array){
..
}
Which will enable me to do things with the array values - but I would like to use the keys as well.
I know there is a Perl hash which allows you to set up key-value pairs, but I just want the index number that the array automatically gives you.
If you're using Perl 5.12.0 or above you can use each on arrays:
my #array = 100 .. 103;
while (my ($key, $value) = each #array) {
print "$key\t$value\n";
}
Output:
0 100
1 101
2 102
3 103
perldoc each
Try:
my #array=(4,5,2,1);
foreach $key (keys #array) {
print $key." -> ".$array[$key]."\n";
}
Works for Hashes and Arrays.
In case of Arrays the $key holds the index.
I guess the closest Perl is something like this:
foreach my $key (0 .. $#array) {
my $value = $array[$key];
# Now $key and $value contains the same as they would in the PHP example
}
Since Perl 5.12.0, you can use the keys function on arrays as well as hashes. That might be a little more readable.
use 5.012;
foreach my $key (keys #array) {
my $value = $array[$key];
# Now $key and $value contains the same as they would in the PHP example
}
I am writing a foreach that does not start at the 0th index but instead starts at the first index of my array. Is there any way to offset the loop's starting point?
Keep it simple.
foreach ($arr as $k => $v) {
if ($k < 1) continue;
// your code here.
}
See the continue control structure in the manual.
A Foreach will reset the array:
Note: When foreach first starts executing, the internal array pointer is automatically reset to the first element of the array. This means that you do not need to call reset() before a foreach loop.
Either use a for loop (only if this is not an associative array)
$letters = range('a','z');
for($offset=1; $offset < count($letters); $offset++) {
echo $letters[$offset];
}
or a while loop (can be any array)
$letters = range('a','z');
next($letters);
while($letter = each($letters)) {
echo $letter['value'];
}
or with a LimitIterator
$letters = new LimitIterator(new ArrayIterator(range('a','z')), 1);
foreach($letters as $letter) {
echo $letter;
}
which lets you specify start offset and count through the constructor.
All of the above will output the letters b to z instead of a to z
You can use the array_slice function:
$arr = array(); // your array
foreach(array_slice($arr, 1) as $foo){
// do what ever you want here
}
Of course, you can use whatever offset value you want. In this case, 1 'skip' the first element of the array.
In a foreach you cant do that. There are only two ways to get what you want:
Use a for loop and start at position 1
use a foreach and use a something like if($key>0) around your actual code
A foreach does what its name is telling you. Doing something for every element :)
EDIT: OK, a very evil solution came just to my mind. Try the following:
foreach(array_reverse(array_pop(array_reverse($array))) as $key => $value){
...
}
That would reverse the array, pop out the last element and reverse it again. Than you'll have a element excluding the first one.
But I would recommend to use one of the other solutions. The best would be the first one.
And a variation: You can use array_slice() for that:
foreach(array_slice($array, 1, null, true) as $key => $value){
...
}
But you should use all three parameters to keep the keys of the array for your foreach loop:
Seems like a for loop would be the better way to go here, but if you think you MUST use foreach you could shift the first element off the array and unshift it back on:
$a = array('foo','bar');
$temp = array_shift($a);
foreach ( $a as $k => $v ) {
//do something
}
array_unshift($a, $temp);
Well no body said it but if you don't mind altering the array and if we want to start from the second element of the given array:
unset($array[key($array)]);
foreach($array as $key=>$value)
{
//do whatever
}
if you do mind, just add,
$saved = $array;
unset($array[key($array)]);
foreach($array as $key=>$value)
{
//do whatever
}
$array = $saved;
Moreover if you want to skip a given known index, just subtitute
key($array)
by the given index
bismillah...
its simple just make own keys
$keys=1;
foreach ($namafile_doc as $value ) {
$data['doc'.$keys]=$value;
$keys++;
}
may this answer can make usefull