This question already has answers here:
Reference Guide: What does this symbol mean in PHP? (PHP Syntax)
(24 answers)
Closed 9 years ago.
In order to be able to directly modify array elements within the loop precede $value with &. In that case the value will be assigned by reference from http://php.net/manual/en/control-structures.foreach.php.
$arr = array(1, 2, 3, 4);
foreach ($arr as &$value) {
echo $value;
}
$arr = array(1, 2, 3, 4);
foreach ($arr as $value) {
echo $value;
}
In both cases, it outputs 1234. What does adding & to $value actually do?
Any help is appreciated. Thanks!
It denotes that you pass $value by reference. If you change $value within the foreach loop, your array will be modified accordingly.
Without it, it'll passed by value, and whatever modification you do to $value will only apply within the foreach loop.
In the beginning when learning what passing by reference it isn't obvious....
Here's an example that I hope will hope you get a clearer understanding on what the difference on passing by value and passing by reference is...
<?php
$money = array(1, 2, 3, 4); //Example array
moneyMaker($money); //Execute function MoneyMaker and pass $money-array as REFERENCE
//Array $money is now 2,3,4,5 (BECAUSE $money is passed by reference).
eatMyMoney($money); //Execute function eatMyMoney and pass $money-array as a VALUE
//Array $money is NOT AFFECTED (BECAUSE $money is just SENT to the function eatMyMoeny and nothing is returned).
//So array $money is still 2,3,4,5
echo print_r($money,true); //Array ( [0] => 2 [1] => 3 [2] => 4 [3] => 5 )
//$item passed by VALUE
foreach($money as $item) {
$item = 4; //would just set the value 4 to the VARIABLE $item
}
echo print_r($money,true); //Array ( [0] => 2 [1] => 3 [2] => 4 [3] => 5 )
//$item passed by REFERENCE
foreach($money as &$item) {
$item = 4; //Would give $item (current element in array)value 4 (because item is passed by reference in the foreach-loop)
}
echo print_r($money,true); //Array ( [0] => 4 [1] => 4 [2] => 4 [3] => 4 )
function moneyMaker(&$money) {
//$money-array is passed to this function as a reference.
//Any changes to $money-array is affected even outside of this function
foreach ($money as $key=>$item) {
$money[$key]++; //Add each array element in money array with 1
}
}
function eatMyMoney($money) { //NOT passed by reference. ONLY the values of the array is SENT to this function
foreach ($money as $key=>$item) {
$money[$key]--; //Delete 1 from each element in array $money
}
//The $money-array INSIDE of this function returns 1,2,3,4
//Function isn't returing ANYTHING
}
?>
This is reference to a variable and the main use in foreach loop is that you can change the $value variable and that way the array itself would also change.
when you're just referencing values, you won't notice much difference in the case you've posted. the most simple example I can come up with describing the difference of referencing a variable by value versus by reference is this:
$a = 1;
$b = &$a;
$b++;
print $a; // 2
You'll notice $a is now 2 - because $b is a pointer to $a. if you didn't prefix the ampersand, $a would still be 1:
$a = 1;
$b = $a;
$b++;
print $a; // 1
HTH
Normally every function creates a copy of its parameters, works with them, and if you don't return them "deletes them" (when this happens depends on the language).
If run a function with &VARIABLE as parameter that means you added that variable by reference and in fact this function will be able to change that variable even without returning it.
Related
I'm trying to build a function to count all the items of an array containing a given parameter, but, if the parameter is not given when calling the function, the function should count all the items. Parameters are passed with an array $params: This is what I have done so far:
function myfunction($params){
global $myArray;
if ( !isset($params[0]) ){ $params[0] = ???????? } // I need a wildcard here, so that, if the parameter is not given, the condition will be true by default
if ( !isset($params[1]) ){ $params[1] = ???????? } // I need a wildcard here, so that, if the parameter is not given, the condition will be true by default
....etc......
foreach($myArray as $item){
if ($item[0] == $params[0]){ // this condition should be true if parameter is not given
if ($item[1] == $params[1]){// this condition should be true if parameter is not given
$count += $item
}
}
}
return $count;
}
I would like:
myfunction(); //counts everything
myfunction( array ('0' => 'banana') ); //counts only $myArray['0'] = banana
myfunction( array ('0' => 'apple', '1' => 'eggs') ); //counts only $myArray['0'] = apples and $myArray['1'] = eggs
I have several $params[keys] to check this way.
I guess, if I should assign a default value to params[key] (like a wildcard) , so that, if it is not given, the function will take all the $item. I mean something that $item[0] will always be (==) equal to. Thanks. [See my answer for solution]
The way your function is declared, you have to pass a parameter. What you want to do is have a default value so that your code inside the function can detect that:
function myfunction($params=NULL)
{
global $myArray;
if (empty($params))
{
// count everything
}
else
{
// count what's listed in the $params array
}
}
EDIT
If I read your comments correctly, $myArray looks something like this:
$myArray=array
(
'apple'=>3, // 3 apples
'orange'=>4, // 4 oranges
'banana'=>2, // 2 bananas
'eggs'=>12, // 12 eggs
'coconut'=>1, // 1 coconut
);
Assuming that's true, what you want is
function myfunction($params=NULL)
{
global $myArray;
$count=0;
if (empty($params)) // count everything
{
foreach ($myArray as $num) // keys are ignored
$count += $num;
}
else if (!is_array($params)) // sanity check
{
// display an error, write to error_log(), etc. as appropriate
}
else // count what's listed in the $params array
{
foreach ($params as $key) // check each item listed in $params
if (isset($myArray[$key])) // insure request in $myArray
$count += $myArray[$key]; // add item's count to total
}
return $count;
}
This will give you
myfunction(); // returns 22
myfunction(array('banana')); // returns 2
myfunction(array('apple','eggs')); // returns 15
myfunction(array('tomatoes')); // returns 0 - not in $myArray
If this isn't the result you're looking for, you need to rewrite your question.
EDIT # 2
Note that because arrays specified without explicit keys are keyed numerically in the order the elements are listed, the function calls I showed above are exactly equivalent to these:
myfunction(); // returns 22
myfunction(array(0=>'banana')); // returns 2
myfunction(array(0=>'apple',1=>'eggs')); // returns 15
myfunction(array(0=>'tomatoes')); // returns 0 - not in $myArray
However, the calls are not equivalent to these:
myfunction(); // returns 22
myfunction(array('0'=>'banana')); // returns 2
myfunction(array('0'=>'apple','1'=>'eggs')); // returns 15
myfunction(array('0'=>'tomatoes')); // returns 0
In this case, explicit string keys are specified for the array, and while the strings' values will evaluate the same as the numerical indices under most circumstances, string indices are not the same as numerical ones.
The code you proposed in your answer has a few errors:
foreach($myArray as $item)
{
foreach ($params as $key => $value)
{
if ( isset($params[$key]) && $params[$key] == $item[$key] )
{
$count += $item
}
}
}
First, isset($params[$key]) will always evaluate to TRUE by the nature or arrays and foreach. Second, because of your outer foreach loop, if your $myArray is structured as I illustrated above, calling myfunction(array('apple')) will result in $params[$key] == $item[$key] making these tests because $key is 0:
'apple' == 'apple'[0] // testing 'apple' == 'a'
'apple' == 'orange'[0] // testing 'apple' == 'o'
'apple' == 'banana'[0] // testing 'apple' == 'b'
'apple' == 'eggs'[0] // testing 'apple' == 'e'
'apple' == 'coconut'[0] // testing 'apple' == 'c'
As you can see, this will not produce the expected results.
The third problem with your code is you don't have a semicolon at the end of the $count += $item line, so I'm guessing you didn't try running this code before proposing it as an answer.
EDIT # 3
Since your original question isn't terribly clear, it occurred to me that maybe what you're trying to do is count the number of types of things in $myArray rather than to get a total of the number of items in each requested category. In that case, the last branch of myfunction() is even simpler:
else // count what's listed in the $params array
{
foreach ($params as $key) // check each item listed in $params
if (isset($myArray[$key])) // insure request in $myArray
$count++; // add the item to the total
}
With the sample $myArray I illustrated, the above change will give you
myfunction(); // returns 5
myfunction(array('banana')); // returns 1
myfunction(array('apple','eggs')); // returns 2
myfunction(array('tomatoes')); // returns 0 - not in $myArray
Again, if neither of these results are what you're looking for, you need to rewrite your question and include a sample of $myArray.
MY SOLUTION
(Not extensively tested, but works so far)
Following #FKEinternet answer, this is the solution that works for me: obviously the $params should use the same keys of $item. So, foreach iteration if parameter['mykey'] is given when calling the function and its value is equal to item['mykey'], count the iteration and $count grows of +1
function myfunction($params=NULL){
global $myArray;
foreach($myArray as $item){
foreach ($params as $key => $value){
if ( isset($params[$key]) && $params[$key] == $item[$key] ){
$count += $item;
}
}
}
return $count;
}
Thanks everybody for all inputs!!
I am trying to make a function where I get data from specific positions in an array, and then add(plus) the results together. Something like this:
$specificPositionsInArray = "1,4,12,27,40,42,48,49,52,53,56,58";
$dataArray = "1,2,3,4,5,6,7,8"; // More than hundred values.
myfunction($specificPositionsInArray) {
// Find position in array, based on $specificPositionsInArray and then
// plus the value with the previous value
// that is found in the $specificPositionsInArray.
// Something like:
$value = $value + $newValue;
return $value;
}
So if $specificPositionsInArray was 1,3,5
The $value that should be returned would be: 9 (1+3+5) (based on the $dataArray).
Maybe there is another way to do it, like without the function.
Here's a functional approach:
$specificPositionsInArray = array(1,3,7,6);
$dataArray = array(1,2,3,4,5,6,7,8);
function totalFromArrays($specificPositionsInArray, $dataArray) {
foreach ($specificPositionsInArray as $s){
$total += $dataArray[$s];
}
return $total;
}
$total = totalFromArrays($specificPositionsInArray, $dataArray);
echo $total;
You should look into arrays and how to handle them, you could have found the solution pretty easily. http://www.php.net/manual/en/book.array.php
//$specificPositionsInArray = array(1,4,12,27,40,42,48,49,52,53,56,58);
$specificPositionsInArray = array(1,3,5);
$dataArray = array(1,2,3,4,5,6,7,8);
$total=0;
foreach($specificPositionsInArray as $k => $v){
$total += $dataArray[$v-1];
}
echo $total;
The weird part about this is the $v-1 but because of how you want to handle the addition of the items, and an array starts with element 0, you have to subtract 1 to get to the right value.
So you want to do something like this:
$dataArray = array(1,2,3,4,5...); // 100+ values, not necessarily all integers or in ascending order
$specificPositions = array(1, 3, 5);
function addSpecificPositions($data, $positions) {
$sum = 0;
foreach($positions as $p)
$sum += $data[$p];
return $sum;
}
If you really want to keep your list of values in a string (like you have it in your example), you'll have to do an explode first to get them in array form.
Since it looks like your array is using numeric values for the keys this should be fairly easy to calculate. I refactored your code a little to make it easier to read:
$specificPositionsInArray = array(1,4,6,7);
By default PHP will assign numeric keys to each value in your array, so it will look like this to the interpreter.
array(
[0] => 1,
[1] => 4,
[2] => 6,
[3] => 7
)
This is the same for all arrays unless you specify a numeric or mixed key. Since the data array seems to just be values, too, and no keys are specified, you can simply target them with the key that they will be associated with. Say I use your array example:
$dataArray = array(1,2,3,4,5,6,7,8);
This will look like this to the parser:
array(
[0] => 1,
[1] => 2,
[2] => 3,
[3] => 4,
[4] => 5,
[5] => 6,
[6] => 7,
[7] => 8
)
If you wanted to select the number 6 from this array, you actually need to use $dataArray[5] since array keys start at zero. So for your function you would do this:
$specificPositionsInArray = array(1,4,6,7);
$dataArray = array(1,2,3,4,5,6,7,8);
calculate_array($specificPositionsInArray, $dataArray); // Returns 18
function calculate_array($keys, $data){
$final_value = 0; // Set final value to 0 to start
// Loop through values
foreach($keys as $key){
// Add the keys to our starting value
$final_value += $data[$key-1]; // minus 1 from key so that key position is human readable
}
// return the sum of the values
return $final_value;
}
This question already has answers here:
php - how to remove all elements of an array after one specified
(3 answers)
Closed 9 years ago.
Is it possible to delete all array elements after an index?
$myArrayInit = array(1=>red, 30=>orange, 25=>velvet, 45=>pink);
now some "magic"
$myArray = delIndex(30, $myArrayInit);
to get
$myArray = array(1=>red, 30=>orange);
due to the keys in $myArray are not successive, I don't see a chance for array_slice()
Please note : Keys have to be preserved! + I do only know the Offset Key!!
Without making use of loops.
<?php
$myArrayInit = [1 => 'red', 30 => 'orange', 25 => 'velvet', 45 => 'pink']; //<-- Your actual array
$offsetKey = 25; //<--- The offset you need to grab
//Lets do the code....
$n = array_keys($myArrayInit); //<---- Grab all the keys of your actual array and put in another array
$count = array_search($offsetKey, $n); //<--- Returns the position of the offset from this array using search
$new_arr = array_slice($myArrayInit, 0, $count + 1, true);//<--- Slice it with the 0 index as start and position+1 as the length parameter.
print_r($new_arr);
Output :
Array
(
[1] => red
[30] => orange
[25] => velvet
)
Try
$arr = array(1=>red, 30=>orange, 25=>velvet, 45=>pink);
$pos = array_search('30', array_keys($arr));
$arr= array_slice($arr,0,$pos+1,true);
echo "<pre>";
print_r($arr);
See demo
I'd iterate over the array up until you reach the key you want to truncate the array thereafter, and add those items to a new - temporary array, then set the existing array to null, then assign the temp array to the existing array.
This uses a flag value to determine your limit:
$myArrayInit = array(1=>'red', 30=>'orange', 25=>'velvet', 45=>'pink');
$new_array = delIndex(30,$myArrayInit);
function delIndex($limit,$array){
$limit_reached=false;
foreach($array as $ind=>$val){
if($limit_reached==true){
unset($array[$ind]);
}
if($ind==$limit){
$limit_reached=true;
}
}
return $array;
}
print_r($new_array);
Try this:
function delIndex($afterIndex, $array){
$flag = false;
foreach($array as $key=>$val){
if($flag == true)
unset($array[$key]);
if($key == $afterIndex)
$flag = true;
}
return $array;
}
This code is not tested
If I iterate through an array twice, once by reference and then by value, PHP will overwrite the last value in the array if I use the same variable name for each loop. This is best illustrated through an example:
$array = range(1,5);
foreach($array as &$element)
{
$element *= 2;
}
print_r($array);
foreach($array as $element) { }
print_r($array);
Output:
Array ( [0] => 2 [1] => 4 [2] => 6 [3] => 8 [4] => 10 )
Array ( [0] => 2 [1] => 4 [2] => 6 [3] => 8 [4] => 8 )
Note that I am not looking for a fix, I am looking to understand why this is happening. Also note that it does not happen if the variable names in each loop are not each called $element, so I'm guessing it has to do with $element still being in scope and a reference after the end of the first loop.
After the first loop $element is still a reference to the last element/value of $array.
You can see that when you use var_dump() instead of print_r()
array(5) {
[0]=>
int(2)
...
[4]=>
&int(2)
}
Note that & in &int(2).
With the second loop you assign values to $element. And since it's still a reference the value in the array is changed, too. Try it with
foreach($array as $element)
{
var_dump($array);
}
as the second loop and you'll see.
So it's more or less the same as
$array = range(1,5);
$element = &$array[4];
$element = $array[3];
// and $element = $array[4];
echo $array[4];
(only with loops and multiplication ...hey, I said "more or less" ;-))
Here's an explanation from the man himself:
$y = "some test";
foreach ($myarray as $y) {
print "$y\n";
}
Here $y is a symbol table entry referencing a string containing "some
test". On the first iteration you essentially do:
$y = $myarray[0]; // Not necessarily 0, just the 1st element
So now the storage associated with $y
is overwritten by the value from
$myarray. If $y is associated with
some other storage through a
reference, that storage will be
changed.
Now let's say you do this:
$myarray = array("Test");
$a = "A string";
$y = &$a;
foreach ($myarray as $y) {
print "$y\n";
}
Here $y is associated with the same
storage as $a through a reference so
when the first iteration does:
$y = $myarray[0];
The only place that "Test" string can
go is into the storage associated with
$y.
This is how you would fix this problem:
foreach($array as &$element)
{
$element *= 2;
}
unset($element); #gets rid of the reference and cleans the var for re-use.
foreach($array as $element) { }
I'd like to be able to extract some array elements, assign each of them to a variable and then unset these elements in the array.
Let's say I have
$myarray = array ( "one" => "eins", "two" => "zwei" , "three" => "drei") ;
I want a function suck("one",$myarray)as a result the same as if I did manually:
$one = "eins" ;
unset($myarray["one"]) ;
(I want to be able to use this function in a loop over another array that contains the names of the elements to be removed, $removethese = array("one","three") )
function suck($x, $arr) {
$x = $arr[$x] ;
unset($arr[$x]) ;
}
but this doesn't work. I think I have two prolbems -- how to say "$x" as the variable to be assigned to, and of function scope. In any case, if I do
suck("two",$myarray) ;
$two is not created and $myarray is unchanged.
Try this:
$myarray = array("one" => "eins", "two" => "zwei" , "three" => "drei");
suck('two', $myarray);
print_r($myarray);
echo $two;
function suck($x, &$arr) {
global $$x;
$$x = $arr[$x];
unset($arr[$x]);
}
Output:
Array
(
[one] => eins
[three] => drei
)
zwei
I'd build an new array with only the key => value pairs you want, and then toss it at extract().
You can do
function suck($x, $arr) {
$$x = $arr[$x] ;
unset($arr[$x]) ;
}
, using variable variables. This will only set the new variable inside the scope of "suck()".
You can also have a look at extract()
Why not this:
foreach ($myarray as $var => $val) {
$$var = $val;
unset($myarray[$var]);
echo "$var => ".$$var . "\n";
}
Output
one => eins
two => zwei
three => drei
If I've understood the question, you have two problems
The first is that you're setting the value of $x to be the value in the key-value pair. Then you're unsetting a key that doesn't exist. Finally, you're not returning anything. Here's what I mean:
Given the single element array $arr= array("one" => "eins") and your function suck() this is what happens:
First you call suck("one", $arr). The value of $x is then changed to "eins" in the line $x=$arr[$x]. Then you try to unset $x (which is invalid because you don't have an array entry with the key "eins"
You should do this:
function suck($x, $arr)
{
$tmp = $arr[$x];
unset($arr[$x]);
return $tmp
}
Then you can call this function to get the values (and remove the pair from the array) however you want. Example:
<?php
/* gets odd numbers in german from
$translateArray = array("one"=>"eins", "two"=>"zwei", "three"=>"drei");
$oddArray = array();
$oddArray[] = suck($translateArray,"one");
$oddArray[] = suck($translateArray, "three");
?>
The result of this is the array called translate array being an array with elements("eins","drei");
HTH
JB