Are php5 function parameters passed as references or as copies? - php

Are Php function parameters passed as references to object or as copy of object?
It's very clear in C++ but in Php5 I don't know.
Example:
<?php
$dom = new MyDocumentHTMLDom();
myFun($dom);
Is parameter $dom passed as a reference or as a copy?

In PHP5, objects are passed by reference. Well, not exactly in technical way, because it's a copy - but object variables in PHP5 are storing object IDENTIFIER, not the object itself, so essentially it's the same as passing by reference.
More here:
http://www.php.net/manual/en/language.oop5.references.php

Objects are always pass by reference, so any modifications made to the object in your function are reflected in the original
Scalars are pass by reference. However, if you modify the scalar variable in your code, then PHP will take a local copy and modify that... unless you explicitly used the & to indicate pass by reference in the function definition, in which case modification is to the original

In PHP5, the default for objects is to pass by reference.
Here is one blog post that highlights this: http://mjtsai.com/blog/2004/07/15/php-5-object-references/

Copy, unless you specify, in your case, &$dom in your function declaration.
UPDATE
In the OP, the example was an object. My answer was general and brief. Tomasz Struczyński provided an excellent, more detailed answer.

in php5 objects pass by reference, in php4 and older - by value(copy) to pass by reference in php4 you must set & before object's name

It has nothing to do with function parameters. PHP 5 only has pointers to objects; it does not have "objects" as values. So your code is equivalent to this in C++:
MyDocumentHTMLDom *dom = new MyDocumentHTMLDom;
myFun(dom);
Now, many people mentioned pass by value or pass by reference. You didn't ask about this in the question, but since people mention it, I will talk about it. Like in C++ (since you mentioned you know C++), pass by value or pass by reference is determined by how the function is declared.
A parameter is pass by reference if and only if it has a & in the function declaration:
function myFun(&$dom) { ... }
just like in C++:
void myFun(MyDocumentHTMLDom *&dom) { ... }
If it does not, then it is pass by value:
function myFun($dom) { ... }
just like in C++:
void myFun(MyDocumentHTMLDom *dom) { ... }

Related

Cannot access variable property with getter method

In PHP, I cannot assign a value to a variable unless I access its property without using a getter method, is it by design or I missed something?
Simply put, when I do $article->content->value[$some_value] = 'hello' it works, but $article->get_value()[$some_value] = 'hello' sets nothing, the array remains empty.
What the get_value does is just return $this->content->value, and when used as a getter, it does what it supposed to do as expected.
I feel like I missed some basic here, if someone could share me why setting value doesn't work, it'll be great.
Unlike objects, arrays aren't returned by reference in PHP, so when you call the getter method, you're getting back a copy.
If you want to modify the object property itself then you can change the method definition to return a reference by prepending the method name with an ampersand, e.g.
public function &getArray()
{
return $this->array;
}
See https://3v4l.org/1YK9H for a demo
I should stress that this is absolutely not a common pattern in PHP, other than perhaps a long way back into the PHP 4 days when OOP was a lot less ubiquitous. I certainly wouldn't expect a class I was using to return arrays by reference, and neither would I recommend anyone else doing it. Note that it's not possible to ask the class for a reference, in order to prevent unwanted modifications to private properties - the class has to define the behaviour.
The PHP documentation has more information about returning by reference here: http://php.net/manual/en/language.references.return.php

Passing by reference - how does it work and why is it used?

Take the following code from CodeIgniter's show_error function:
$_error =& load_class('Exceptions', 'core');
The documentation for the load_class function says it acts as a singleton. The function basically takes the given parameters and searches for a class in the appropriate path. It then includes the file if it exists. The function is declared as:
function &load_class(...)
Why does it have the & and what is its purpose? Is $_error declared as such as a result of defining the function like that?
I don't see any point of declaring and using load_class like that. From the source code of load_class(), we can see that it caches loaded objects in an array with the class name as the key. If it is not in the cache, it loads an object given a name, and then stores that object reference into the array. In both cases, it returns the element of the array (by reference).
Returning by reference allows the caller to have a reference to the element of the array. The only things that this allows us to do are:
See later changes to that array element (i.e. the value associated with that key) from the outside reference we have. But this is not applicable, since the load_class function never changes the value associated with a key after it sets it.
Have external code be able to change the element in the array, without the load_class function knowing about it. But this would be a highly dubious practice, to mess with the cache from the outside, and I highly doubt this is something the authors wanted.
So there is no legitimate reason to return by reference. My guess is that it is a leftover from PHP 4, when objects were values, and so assigning or returning an "object value" would copy it. In PHP 5, objects are not values; you can only manipulate them through object references, and assigning or returning an object reference by value never copies the object it points to.
The php documentation seems to explain why you have to uses =& even though the function is marked to return a refrence function &load_class
Returning References
Returning by reference is useful when you want to use a function to
find to which variable a reference should be bound. Do not use
return-by-reference to increase performance. The engine will
automatically optimize this on its own. Only return references when
you have a valid technical reason to do so. To return references, use
this syntax:
<?php class foo {
public $value = 42;
public function &getValue() {
return $this->value;
}
}
$obj = new foo;
$myValue = &$obj->getValue(); // $myValue is a reference to $obj->value, which is 42.
$obj->value = 2;
echo $myValue;
// prints the new value of $obj->value, i.e. 2. ?>
In this example,
the property of the object returned by the getValue function would be
set, not the copy, as it would be without using reference syntax.
Note: Unlike parameter passing, here you have to use & in both places
- to indicate that you want to return by reference, not a copy, and to indicate that reference binding, rather than usual assignment, should
be done for $myValue.
If you are asking what references in general are the documentation explains.

Can I extract function return value?

I noticed that in PHP extract(some_function()); will work just like:
$stuff = some_function();
extract($stuff);
But in the PHP's documentation the extract function argument has the & thingy in front, and from what I know that means you have to pass a variable to it.
If the documentation was right, this would produce a strict standards message:
PHP Strict standards: Only variables should be passed by reference
So I think you just found a bug in the documentation. Congratulations.
EDIT
It still doesn't complain if you use it with EXTR_REFS as a second argument:
~❯ php -a
Interactive shell
php > function a(){return array('pwet'=> 42);}
php > extract(a(), EXTR_REFS);
php > echo $pwet;
42
Which is strange because referencing variables defined inside a function doesn't make much sense to me. I think the & might have been introduced because of this option, but appears only in the doc and is not enforced in the code.
EDIT
It seems I'm right, I found this comment in ext/standard/array.c (branches 5.3 and 5.4):
/* var_array is passed by ref for the needs of EXTR_REFS (needs to
* work on the original array to create refs to its members)
* simulate pass_by_value if EXTR_REFS is not used */
The ampersand passes a variable by reference so that when it is used in a function, you are manipulating the original object -- not a new variable with the same value. The documentation is telling you that if you pass a variable to the extract function, then the original object can be updated in some fashion by that function.
So, the answer is yes, you need to pass a variable to that function.
The reason $var_array parameter of the extract function is passed by reference (most likely) is from a holdover from older versions of PHP. Newer versions automatically pass arrays by reference.
The extract function creates a variable list from the contents of a (potentially large) array and it is not recommended that data of that type be passed by value.
Long story short, assign your array to a variable and pass it in that way.

when do we need to create pass/call by reference function

I will always be in confusion whether to create pass/call by reference functions. It would be great if someone could explain when exactly I should use it and some realistic examples.
A common reason for calling by reference (or pointers) in other languages is to save on space - but PHP is smart enough to implement copy-on-write for arguments which are declared as passed-by-value (copies). There are also some hidden semantic oddities - although PHP5 introduced the practice of always passing objects by reference, array values are always stored as references, call_user_func() always calls by value - never by reference (because it itself is a function - not a construct).
But this is additional to the original question asked.
In general its good practice to always declare your code as passing by value (copy) unless you explicitly want the value to be different after the invoked functionality returns. The reason being that you should know how the invoked functionality changes the state of the code you are currently writing. These concepts are generally referred to as isolation and separation of concerns.
Since PHP 5 there is no real reason to pass values by reference.
One exception is if you want to modify arrays in-place. Take for example the sort function. You can see that the array is passed by reference, which means that the array is sorted in place (no new array is returned).
Or consider a recursive function where each call needs to have access to the same datum (which is often an array too).
In php4 it was used for large variables. If you passed an array in a function the array was copied for use in the function, using a lot of memory and cpu. The solution was this:
function foo(&$arr)
{
echo $arr['value'];
}
$arr = new array();
foo($arr);
This way you only passed the reference, a link to the array and save memory and cpu. Since php5 every object and array (not sure of scalars like int) are passed by reference internally so there isn't any need to do it yourself.
This is best when your function will always return a modified version of the variable that is passed to it to the same variable
$var = modify($var);
function modify($var)
{
return $var.'ret';
}
If you will always return to the passed variable, using reference is great.
Also, when dealing with large variables and especially arrays, it is good to pass by reference wherever feasible. This helps save on memory.
Usually, I pass by reference when dealing with arrays since I usually return to the modified array to the original array.

Symbol in PHP I've never come across before

I probably should have, but I've never seen this before. Ran into it when looking over the documenation of a Smarty Plugin.
$smarty =& new Smarty;
The =& sign in particular. If you enter it in Google, it gets ignored, just like any other search engine. What is this used for?
Same goes for this function signature:
function connect(&$smarty, $reset = false)
Why the & symbol?
Actually, this code is written to be compatible with PHP 4. The ampersand is useless in PHP 5 (as Tim said - since PHP 5, all objects are passed by reference).
With PHP 4, all variables were passed by value.
If you wanted to pass it by reference, you had to declare a reference assignment :
$ref_on_my_object =& new MyObject();
This code is still accepted with PHP 5 default configuration, but it's better to write :
$ref_on_my_object = new MyObject(); // Reference assignment is implicit
For your second problem, the issue is "almost" the same...
Because PHP lets you declare function arguments (resp. types), and you can't do it for return values.
An accepted, but "not so good" practice is to avoid reference declaration within the function's declaration :
function foo($my_arg) {
// Some processing
}
and to call with a reference...
$my_var;
$result = foo( &$my_var );
// $my_var may have changed because you sent the reference to the function
The ideal declaration would be more like :
function foo( & $my_input_arg ) {
// Some processing
}
then, the call looses the ampersand :
$my_var;
$result = foo( $my_var );
// $my_var may have changed because you sent the reference to the function
It is used for passing values by reference rather than by value which is default in php.
& passes an argument by reference. In this fashion, connect() can manipulate the $smarty object so that the calling function can retrieve the modified object.
Similarly, =& sets a variable by reference.
As Tim said its a reference to a variable. But if you're using a recent version of PHP then all class object are passed by reference anyway. You would still need this if you were passing about arrays, or other builtin types though.
The first example is returning reference, the second is passing reference.
You can read all about it in the PHP manual
& is PHP's reference operator. It's used to return a reference to the object. In this case "new Smarty".
The ampersand will assign a reference to the variable, rather than the value of the object.
One of the primary uses of the ampersand operator is to pass by memory address. This is usually something you do when you want to have a variable changed, but not be returned.
function test_array(&$arr)
{
$varr[] = "test2";
}
$var = array('test');
test_array($var);
print_r($var);
this should output
array( test , test2 );
The purpose of this is usually when you need to pass the actual copy[memory address] you are working with into another function / object. Typically it was used in the past to alleviate a lack of memory and speed up performance, it's a feature from C / C++ and a few other low level languages.

Categories