Can I extract function return value? - php

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.

Related

CodeIgniter - & operator

What exactly does the following line of code doing:
$config = &get_config();
Is & operator passing by reference? Also is get_config() a CodeIgniter helper? I couldn't Google the explanation.
As Konrad Rudolph said here: https://stackoverflow.com/a/3957588/837765
The & operator tells PHP not to copy the array when passing it to the
function. Instead, a reference to the array is passed into the
function, thus the function modifies the original array instead of a
copy.
get_config() loads the main config.php file in an array and you modify the returns array directly with the & operator.
It's not a helper. Take a look here (to find the get_config() function) :
http://www.8tiny.com/source/codeigniter/nav.html?_functions/index.html
Is & operator passing by reference?
Yes, it is passed by reference so that you can change config array.
Also is get_config() a CodeIgniter helper?
No, it's a core CodeIgniter method which loads the config array defined in application/config/config.php.
You can look at the source here.
The & operator is PHP's reference operator.
CodeIgniter is a rather old framework. In older versions of PHP objects used to be passed by value. This meant that PHP was quite wasteful when it came to stuff like memory allocation, which made things slower than they needed to be. To prevent PHP from allocating memory every time you wanted to access an object you would instead use references.
In newer versions of PHP objects and arrays are automatically passed by reference. When it comes to arrays, new memory is only allocated if you change the array.
99 per cent of the time using references is not necessary. PHP will optimize the code for you in a way that makes sense. You should only use references if you understand what they do, and you have a legit reason to use them.
You can find the get_config() function by searching for it in the source code on GitHub.

Is it correct to use end(explode($delim, $str)) in PHP 5.3?

An excerpt from the manual about the returned result:
The array. This array is passed by reference because it is modified by
the function. This means you must pass it a real variable and not a
function returning an array because only actual variables may be
passed by reference.
I use end(explode( and it works without any warnings or notices, but I have PHP 5.4 on the localhost and the product requirements are "PHP 5.3 or higher". I read about the function array dereferencing which had appeared in 5.4, but I thought it worked only for the square brackets array element dereferencing.
Could somebody please clear the matter for me? Or at least give me some links about inner workings of PHP. There is a handy technical reference for JavaScript, I could make use of something like it for PHP.
As of PHP 5.4 it is possible to array dereference the result of a function or method call directly. Before it was only possible using a temporary variable.
it creates temporary variable automatically

Why does PHP's call_user_func() function not support passing by reference?

Why don't the function handling functions like call_user_func() support passing parameters by reference?
The docs say terse things like "Note that the parameters for call_user_func() are not passed by reference." I assume the PHP devs had some kind of reason for disabling that capability in this case.
Were they facing a technical limitation? Was it a language design choice? How did this come about?
EDIT:
In order to clarify this, here is an example.
<?php
function more(&$var){ $var++; }
$count = 0;
print "The count is $count.\n";
more($count);
print "The count is $count.\n";
call_user_func('more', $count);
print "The count is $count.\n";
// Output:
// The count is 0.
// The count is 1.
// The count is 1.
This is functioning normally; call_user_func does not pass $count by reference, even though more() declared it as a referenced variable. The call_user_func documentation clearly says that this is the way it's supposed to work.
I am well aware that I can get the effect I need by using call_user_func_array('more', array(&$count)).
The question is: why was call_user_func designed to work this way? The passing by reference documentation says that "Function definitions alone are enough to correctly pass the argument by reference." The behavior of call_user_func is an exception to that. Why?
The answer is embedded deep down in the way references work in PHP's model - not necessarily the implementation, because that can vary a lot, particularly in the 5.x versions. I'm sure you've heard the lines, they're not like C pointers, or C++ references, etc etc... Basically when a variable is assigned or bound, it can happen in two ways - either by value (in which case the new variable is bound to a new 'box' containing a copy of the old value), or by reference (in which case the new variable is bound to the same value box as the old value). This is true whether we're talking about variables, or function arguments, or cells in arrays.
Things start to get a bit hairy when you start passing references into functions - obviously the intent is to be able to modify the original variables. Quite some time ago, call-time pass-by-reference (the ability to pass a reference into a function that wasn't expecting one) got deprecated, because a function that wasn't aware it was dealing with a reference might 'accidentally' modify the input. Taking it to another level, if that function calls a second function, that itself wasn't expecting a reference... then everything ends up getting disconnected. It might work, but it's not guaranteed, and may break in some PHP version.
This is where call_user_func() comes in. Suppose you pass a reference into it (and get the associated the call-time pass-by-reference warning). Then your reference gets bound to a new variable - the parameters of call_user_func() itself. Then when your target function is called, its parameters are not bound where you expect. They're not bound to the original parameters at all. They're bound to the local variables that are in the call_user_func() declaration. call_user_func_array() requires caution too. Putting a reference in an array cell could be trouble - since PHP passes that array with "copy-on-write" semantics, you can't be sure if the array won't get modified underneath you, and the copy won't get detached from the original reference.
The most insightful explanation I've seen (which helped me get my head around references) was in a comment on the PHP 'passing by reference' manual:
http://ca.php.net/manual/en/language.references.pass.php#99549
Basically the logic goes like this. How would you write your own version of call_user_func() ? - and then explain how that breaks with references, and how it fails when you avoid call-time pass-by-reference. In other words, the right way to call functions (specify the value, and let PHP decide from the function declaration whether to pass value or reference) isn't going to work when you use call_user_func() - you're calling two functions deep, the first by value, and the second by reference to the values in the first.
Get your head around this, and you'll have a much deeper understanding of PHP references (and a much greater motivation to steer clear if you can).
See this:
http://hakre.wordpress.com/2011/03/09/call_user_func_array-php-5-3-and-passing-by-reference/
Is it possible to pass parameters by reference using call_user_func_array()?
http://bugs.php.net/bug.php?id=17309&edit=1
Passing references in an array works correctly.
Updated Answer:
You can use:
call_user_func('more', &$count)
to achieve the same effect as:
call_user_func_array('more', array(&$count))
For this reason I believe (unfoundedly) that call_user_func is just a compiler time short cut. (i.e. it gets replaced with the later at compile time)
To give my view on you actual question "Why was call_user_func designed to work this way?":
It probably falls under the same lines as "Why is some methods strstr and other str_replace?, why is array functions haystack, needle and string functions needle, haystack?
Its because PHP was designed, by many different people, over a long period of time, and with no strict standards in place at the time.
Original Answer:
You must make sure you set the variable inside the array to a reference as well.
Try this and take note of the array(&$t) part:
function test(&$t) {
$t++;
echo '$t is '.$t.' inside function'.PHP_EOL;
}
$t = 0;
echo '$t is '.$t.' in global scope'.PHP_EOL;
test($t);
$t++;
echo '$t is '.$t.' in global scope'.PHP_EOL;
call_user_func_array('test', array(&$t));
$t++;
echo '$t is '.$t.' in global scope'.PHP_EOL;
Should output:
$t is 0 in global scope
$t is 1 inside function
$t is 2 in global scope
$t is 3 inside function
$t is 4 in global scope
Another possible way - the by-reference syntax stays the 'right' way:
$data = 'some data';
$func = 'more';
$func($more);
function more(&$data) {
// Do something with $data here...
}

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.

Are php5 function parameters passed as references or as copies?

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) { ... }

Categories