I just noticed the following behavior in my php code and I'm wondering why it's happening.
$array = array();
test_value($array['invalid_index']); // Error -> Notice: Undefined index: invalid_index in ...
test_reference($array['invalid_index']); //No error
function test_value($value){}
function test_reference(&$value){}
I was expecting both test_value and test_reference to throw the undefined index error but strangely the method by reference doesn't throw any error.
Why?
Function parameters by-reference accept variables which haven't been declared previously; they are being declared by passing them as reference. This makes complete sense if you look at typical use cases of by-reference parameters:
$foo = preg_match('/(.)/', 'bar', $baz);
This function returns one value, which will be assigned to $foo. However, this function should also return the matches, which here is the third parameter $baz. Since a function can only return a single value at a time, additional "return" values are being realised by populating variables passed by reference.
If you had to pre-initialise these variables, your code would look like this:
$baz = null;
$foo = preg_match('/(.)/', 'bar', $baz);
echo $baz[0];
This makes code more complicated than necessary; PHP hence doesn't require that such variables "exist" beforehand.
Related
I have the following code:
$family = cis_resempty(wp_get_post_terms($post->ID,'family'),0);
I get the following error:
Notice: Only variables should be passed by reference in
C:\xampp.....xxx.php on line 18
If I do the following:
$family = cis_resempty(array('a'),0);
I even get
Fatal error: Only variables can be passed by reference in
C:\xampp...xxx.php on line 16
The function cis_resempty is like this (but its from a library):
function cis_resempty(&$var,$key) { ... }
Found out that if I remove the & reference sign within the parameter list of cis_resempty there are no errors.
If I do this:
$family = #cis_resempty(wp_get_post_terms($post->ID,'family'),0);
There is no notice and everything works - but Netbeans says:
Misuse of the error control operator
But if I do this:
$family = #cis_resempty(array('a'),0);
The fatal error continues to exist.
Why can I pass a function by reference and suppress the notice with the error control operator but if I pass an array I get a fatal error?
Why is it bad to pass a non variable by reference?
NOTE: never use '#' for suppressing.
Why can I pass a function by reference and suppress the notice with
the error control operator but if I pass an array I get a fatal error?
Read here Passing by Reference first note:
There is no reference sign on a function call - only on function definitions. Function definitions alone are enough to correctly pass the argument by reference. As of PHP 5.3.0, you will get a warning saying that "call-time pass-by-reference" is deprecated when you use & in foo(&$a);. And as of PHP 5.4.0, call-time pass-by-reference was removed, so using it will raise a fatal error.
PHP doesn't "support" it since 5.4.0 => you get E_FATAL in any case. With # or without #. For function - you get E_STRICT. All right. Then, read about # work more here Error Control Operators. Again, first note:
Note: The #-operator works only on expressions. A simple rule of thumb is: if you can take the value of something, you can prepend the # operator to it. For instance, you can prepend it to variables, function and include calls, constants, and so forth. You cannot prepend it to function or class definitions, or conditional structures such as if and foreach, and so forth.
Try this code ( it will shed light) :
error_reporting(E_ALL);
$arr = [1,2,3,4,5,];
$a_closure = function(){
return [1,2,3,4,5];
};
function a(){
return [1,2,3,4,5];
}
function ref_func(&$input){
foreach($input as &$in){
$in++;
}
}
ref_func($a); // #ref_func($a);
ref_func(a()); // #ref_func($a());
ref_func($a_closure); // #ref_func($a_closure);
// Fatals in both
ref_func([1,2,3,4,5]); // #ref_func([1,2,3,4,5]);
The term "non-variable" refers to any variable which the programmer cannot reference by name. These are temporary variables allocated by the executor at runtime: The result of a function call or some other expression, that is not assigned to a named variable.
To pass something by reference only makes sense if the variable being passed by reference is named, so that when the call is over, the caller can access that which was passed by reference to the callee.
When PHP comes across a function call at compile time, the space for the result of the function call, and parameters of the function call are reserved, and then allocated at execution time relative to the execution frame. When you pass the result of a function call by reference, the executor is able to force by-reference behaviour for the variable, because there is space on the heap and it can just ignore that the variable has no name ... it doesn't usually make sense to do that, but remains for backward compatibility reasons.
When PHP comes across a literal (array) at compile time, it allocates the space for the data relative to the op array (function) itself. Because of that difference forcing by-reference behaviour of literals would be dangerous and cause very unexpected behaviour: Consider what would happen when the function is re-entered, concurrently or otherwise.
The error first appears with the call to JB_do_house_keeping(). This function gets called at every request!
JBPlug_do_callback('jb_init', $A=false); // **ERROR HERE**
define ('JB_INIT_COMPLETED', true);
================================
Then also with JB_save_session():
JBPLUG_do_callback('house_keeping_critical_section', $A = false); // **ERROR HERE**
Please help! I am stuck here: I am a basic coder trying something new...
There are two ways to pass information to a function in PHP:
as a value (e.g. false, 48, 'foobar')
as a reference to a variable (e.g. $a)
Functions define how they want to receive their arguments. If they expect to receive it as a reference, that means that the changes the function makes to the variable will have an effect in the scope where the function was called.
If you provide a value where the function is expecting a reference, the function won't properly do what you expect.
For instance, array_splice expects its first argument to be a reference, so that you can get the modifications made to the array. But imagine if you did this:
array_splice(array('foo', 'bar'), 1);
You've passed in a value, not a reference. The code that called your function can't get the modified array, because array_splice doesn't return it. The correct way is like this:
$array = array('foo', 'bar');
array_splice($array, 1);
echo count($array); // echoes 1
This is because array_splice takes a reference, and so modifies a variable.
In your case, you're doing this:
JBPlug_do_callback('jb_init', $A=false);
Presumably, JBPlug_do_callback is expecting a reference as its second argument. You are providing a value (= returns a value). It may make no difference to what the function does, but technically it's a breach of PHP's rules. (That's why it's a "strict standards" error: it may well not have a bad effect, but it's technically invalid.)
You can solve this, again, simply by providing what PHP wants: a variable:
$A = false;
JBPlug_do_callback('jb_init', $A);
Just playing around and I found this.
Why the call by reference to $this->newAxis() does not throw an undefined property notice (xAxis property), while the var_dump() does?
public function newXAxis()
{
// var_dump(isset($this->xAxis)); // false
// var_dump($this->xAxis); // Throws the notice
return $this->newAxis($this->xAxis); // Should throw the notice?!
}
protected function newAxis(&$current)
{
// ...
}
Does it have something to do with the passing by reference, thus not accessing the property directly?
Yes, it happens because you pass it by reference. When you pass by value, an attempt is made to actually read the value of the variable - so a notice appears. When you pass by reference, the value does not need to be read.
When you do that, the variable/property is created if it does not exist yet.
From the manual:
If you assign, pass, or return an undefined variable by reference, it
will get created.
<?php
function foo(&$var) { }
foo($a); // $a is "created" and assigned to null
newAxis(&$current)
is pass by reference. that means you are passing a variable.
By default all variables in PHP are undefined.
You define them by just using, e.g.
$a = 1;
As you can see, PHP does not complain here that $a is undefined, right?
Okay ;), see here:
$a = $b;
PHP now complains that $b is undefined.
Like with $a (you define the variable) and $b (the variable is not defined) it is with passing by reference or by value:
$this->newAxis($a);
The variable $a is defined when passed by reference. It carries it's default value NULL. And now the $b example:
var_dump($b);
var_dump takes it's parameters by value. Therefore PHP complains that $b is not defined.
And that's all. I hope it was clear enough.
I'm going on a limb here...
Since you are accessing it as an object (from a class) it won't give you a notice, while when you var_dump something it kind of access it like an array (and since it's empty it throws a notice)
Sorry for such a lame title, but I just had no idea what to put there, hope you understand it. Plus, I have no idea if similar question has been asked before, because I don't know the proper keywords for it - therefore couldn't google it too.
Basicly... When looking at preg_match_all();, they got this matches parameter that will create new array defined in function, and give us the ability to access it after function execution.
And the question is.. How can I implement such a feature in my own function? But that it could create single variable and/or array.
Thanks in advance!
preg_match_all() accepts a reference to an array, which in its own scope is called $matches. As seen in the function prototype:
array &$matches
If you call the function and pass in a variable, if it does not already exist in the calling scope it will be created. So in your user-defined function, you accept a parameter by reference using &, then work with it inside your function. Create your outer-scope variable by simply declaring it in your function call, like you the way you call preg_match_all() with $matches.
An example:
function foo(&$bar) {
$bar = 'baz';
}
// Declare a variable and pass it to foo()
foo($variable);
echo $variable; // baz
I think you are referring to function parameters passed by reference, are you not?
function putValInVar(&$myVar, $myVal){
$myVar = $myVal;
}
$myVar = 1;
putValInVar($myVar, 2);
echo $myVar; // outputs '2', but will output '1' if we remove the '&' //
By default function arguments in PHP are passed by value. This means that new variables are created at each function call and those variables will exist only inside the function, not affecting anything outside it.
To specify that an argument should be used by reference the syntax is to append an & before declaring it in the function header. This will instruct PHP to use the passed variable inside the function rather than creating a copy of it.
Exception: Objects are always passed by reference. (Well... Not really, but it's complicated. See the comment thread for more info.)
I think what you are asking for is passing-by-reference. What preg_match_all basically does to "create" an array variable outside its scope is:
function preg_match_all($foo, $bar, & $new_var) {
$new_var = array(1,2,3);
}
The crucial point here is & in the function definition. This allows you to overwrite variables in the outer scope when passed.
Stylistically this should be used with care. Try to return arrays or results instead of doing it via reference passing.
Like this:
$myvariable = runfunction();
function runfunction() {
//do some code assign result to variable (ie $result)
return $result;
}
Or
global $result;
function runfunction() {
global $result;
$result = 'something';
}
Consider:
public function & get($name, $default = null)
Why &?
In PHP's syntax, this means that the function returns a reference instead of a value. For example:
<?php
$foo = 'foo';
function & get_foo_ref ()
{
global $foo;
return $foo;
}
// Get the reference to variable $foo stored into $bar
$bar = & get_foo_ref();
$bar = 'bar';
echo $foo; // Outputs 'bar', since $bar references to $foo.
?>
In the above example, removing the & from the function declaration would make the $foo variable still contain 'foo', since only the value, not the reference was returned from the function.
This was used more often in PHP4, because it did not pass objects by their reference and cloned them instead. Because of this, object variables had to be passed by reference to avoid unwanted cloning. This is no longer the case in PHP5 and references should not be used for this purpose.
However, functions that return references are not completely useless either (or bad practice, when not used for replacing object references).
For example, personally I've used them when creating a script that passes a "path" to an function, which returns reference to variable in that path allowing me to set value to it and read the value. Due to the recursive nature of the function, returning the reference was needed.
By rithiur
It means it returns a reference to the result as opposed to a copy of it.
Returning References in PHP
PHP's pass by reference metacharacter. See Passing by Reference