As I understand, when you pass a variable to a function, and if you don't use reference sign (&) , it means any changes inside your function will not affect to your variable outside the function. In other words, it means the compiler will make a copy of the outside variable to use inside function, doesn't it?
But when I run these testing code, it does not happen like that.
Can anyone explain me what I miss here? Thank you
My test code: the expected result should be 3, but it becomes 1?
function test($arr2) {
foreach($arr2 as &$item) {
$item = 1;
}
}
$arr = array(2);
foreach($arr as &$item2) {
$item2 = 3;
}
test($arr);
print_r($arr);
This issue has been solved a few times before you've asked this (#1). The issue is due to the fact that:
Reference of a $value and the last array element remain even after the
foreach loop. It is recommended to destroy it by unset().
Reference: PHP foreach()
You need to unset the last $item2 after your foreach:
foreach ($arr as &$item2) {
$item2 = 3;
}
unset($item2);
This is quite interesting, it seems like the behavior of array are the same as objects in php in which new array still holds the copy of the members identifier (which points to the same value as the array it was copied from).
As of PHP 5, an object variable doesn't contain the object itself as value anymore. It only contains an object identifier which allows object accessors to find the actual object. When an object is sent by argument, returned or assigned to another variable, the different variables are not aliases: they hold a copy of the identifier, which points to the same object.
PHP Manual - Objects and references
Even though you are not passing $arr as Reference variable, you are still accessing $arr elements as References in function test(). So anything that changes in function will effect outside function too.
If you are looking to change $arr ( which has been passed as $arr2 in test function ) only in test function, then remove &from $item
Related
I'm seeing some confusing behavior related to reference/assignment in PHP...
private function doSomething($things)
{
foreach ($things as $thing) {
echo $thing->property; // 'foobar'
$copyThing = $thing;
unset($copyThing->property);
echo $thing->property; // undefined
I expect this behavior when passing variables by reference (&$thing) but I'm not trying to do that here and it seems to be happening anyway. What am I missing?
Just explaining my comment:
objects in foreach loops are always passed by reference
When you use a foreach loop for an array of objects the variable that you are using inside the loop is a pointer to that object so it works as a reference, any change on the object inside the loop is a change on the object outside.
This is because:
objects are always passed by reference (#user3137702 quote)
Detailed and official explanation here.
When you copy and unset your variable:
$copyThing = $thing;
unset($copyThing->property);
you are creating another pointer and unseting it, so the original value is a gone. As a matter of fact, since the foreach loop also uses a pointer the $things array is also affected.
check this ideone (notice the vardump [where the 'a' property is gone], as the output is the same as you got)
I do not know in which version it changed, if ever, as it seems like default object/pointer behavior
As a workaround (some ideas):
Copy your initial array
Use clone: $x = clone($obj); (As long as the default copy constructor works for your objects)
the array_push(mainArr, subAssociativeArr) does not work when it is inside a function. I need some help with this code:
$store=array();
$samsung=array('id'=>'10','name'=>'samsung');
$sony=array('id'=>'11','name'=>'sony');
function addOne($store, $element){
array_push($store, $element);
}
addOne($store, $samsung);
var_dump($store); //output: empty array
however it works fine if without function; like the following:
$store=array();
$samsung=array('id'=>'10','name'=>'samsung');
$sony=array('id'=>'11','name'=>'sony');
array_push($store, $samsung);
var_dump($store); //output: array is added
so, what is the problem???
You forgot to return
function addOne($store, $element){
$store[]=$element;
return $store;
}
$store = addOne($store, $samsung);
You could also pass by reference if you want to (which is more in line with the code you have):
function addOne(&$store, $element){
$store[]=$element;
}
addOne($store, $samsung);
Note the &. Instead of copying the inputs, this is more like a pointer to the original variable, so you can update it directly. Ether way is fine here, it's a matter of developers choice really. For example it can be very easy to mix the two:
//Don't do this
function addOne(&$store, $element){ //returns null
$store[]=$element;
}
$store = addOne($store, $samsung); //sets $store to null
Which you probably don't want to do, so I can see an argument for both ways. Unless you have super big array, it probably doesn't matter much. It's very easy to forget that a random function is pass by reference.
So use whatever method makes more sense to you.
P.S. - I refuse to use array_push, it's ugly and I don't like it :). Doing $store[]=$element; is the same as array_push($store,$element), except it avoids an unnecessary function call.
Cheers.
When it's in a function, you have a different scope. While the parameters to your addOne function have the same name, they are actually copies of the variables passed, not references to them.
So when you array_push() in a function, you're only affecting the variables in that function's scope, not the outer scope.
You can either return $store, or pass the variables by reference.
If you want it to work within a function you need a reference to the variable. A reference in PHP is defined as & and they are similar to "pointers" in C or C++.
Try this:
function addOne(&$store, $element){
array_push($store, $element);
}
addOne($store, $samsung);
A PHP reference is an alias, which allows two different variables to write to the same value. As of PHP 5, an object variable doesn't contain the object itself as value anymore. It only contains an object identifier which allows object accessors to find the actual object. When an object is sent by argument, returned or assigned to another variable, the different variables are not aliases: they hold a copy of the identifier, which points to the same object.
http://www.php.net/manual/en/language.oop5.references.php
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.
I know that prepending a '&' to your PHP variable sets up a reference to the original variable instead of copying its value like so:
$original = 'apples';
$secondary = &$original;
$original = 'oranges';
echo $secondary; // 'oranges'
If it works this way, why not just use the original variable then?
Passing by reference is useful and necessary when passing a variable as a parameter to a function, expecting that variable to be modified without a copy being created in memory. Many of PHP's native array_*() functions operate on array references, for example.
This function, for example, receives an array reference and appends an element onto the original array. If this was done without the & reference, a new array copy would be created in scope of the function. It would then have to be returned and reassigned to be used.
function add_to_an_array(&$array)
{
// Append a value to the array
$array[] = 'another value';
}
$array = array('one', 'two', 'three');
add_to_an_array($array);
print_r($array);
Array
(
[0] => one
[1] => two
[2] => three
[3] => another value
)
$original = 'apples';
function foo($word) {
$word = 'oranges';
}
foo($original);
echo $original; // apples, because only local $word was changed, not $original.
foo(&$original);
echo $original; // oranges, because $original and $word are the same
Pass by reference is really a cop out and goes against good encapsulation. If you need to manipulate a variable in that way, it probably should belong to a class as a member variable and then does not need to be passed to the function. Good OO design would usually make member variables immutable with a "final" keyword, but PHP doesn't have this. It's not intuitive that passing a variable to a function might change it's value which is why it should be avoided in most cases.
Also going to a more full OO design prevents you have having method signatures that are long and complex with many optional parameters that are difficult to re-factor.
A more interesting use of the is when it's used in the formal argument to a function
foo($a);
...
function foo (&$a) {
....
}
this allows you to modify a in the function.
There are many uses for references.
You can pass a reference to a variable to a function so you can change the value inside the function
You can use references to create linked lists
etc...
Just keep in mind that they're there, and you'll surely find an application for them when the time comes and you face a problem that can be solved with references.
Check out the following article for other ideas and uses of references:
http://www.elated.com/articles/php-references/
I just read this answer by Bill Karwin.
Note that the $node is pass by reference.
I always thought that variable created there is only ever temporary and exists only until the end of the loop (or maybe it remains set to the last iteration - I have not tested it).
So, what are the advantages of making it pass by reference?
I'm sure there is one, but I can't figure it out yet.
It has nothing to do with being faster or more efficient.
PHP implements copy-on-write so a variable may refer to the same area of memory until you change its value. Then when you change the variable, PHP decides whether or not to create a copy depending on whether you're accessing it by value or by reference.
Access by value -- changes to a variable creates a copy:
$a = array("abc");
foreach ($a as $element) {
$element = "def";
}
print_r($a);
Array
(
[0] => abc
)
Access by reference -- changes to a variable affect the original copy:
foreach ($a as &$element) {
$element = "def";
}
print_r($a);
Array
(
[0] => def
)
Note that all objects in PHP 5 are accessed by reference without using the & operator.
This is a good reason to use objects!
Be very careful using references in PHP, because they can have confusing effects.
Be sure to read this blog: Do not use PHP references by PHP core developer Johannes Schlüter
The advantage is that it lets you manipulate the array directly.
foreach ($array as $key => $node) {
$array[$key]['foo'] = 'bar';
}
can be made shorter and more efficient like this:
foreach ($array as &$node) {
$node['foo'] = 'bar';
}
In this case $node is not a copy of the contents of the array entry, but a reference to the actual array entry; whatever you do to it, you do to the array.