The following pattern used to be possible in PHP:
function foo($arr)
{
// modify $arr in some way
return $arr;
}
This could then be called using pass-by-value:
$arr = array(1, 2, 3);
$newarr = foo($arr);
or pass-by-reference:
$arr = array(1, 2, 3);
foo(&$arr);
but "Call-time pass-by-reference has been deprecated". Modifying the function signature:
function foo(&$arr)
will handle the pass-by-reference case, but will break the dual-purpose nature of the original function, since pass-by-value is no longer possible.
Is there any way around this?
I think this is as close as you get:
function foo(&$bar) { ... }
foo($array); // call by reference
$bar = foo($_tmp = $array); // call by value
Unfortunately it will require some changes to every call.
The dual-purpose nature was stupid, which is why the behaviour is deprecated. Modify the function signature, as you suggest.
Sadly, I don't believe there is a way around it.
Just make your function use the reference with &.
A simple workaround is to prepare a wrapper function:
function foo($arr) {
return foo_ref($arr);
}
function foo_ref(&$arr) {
...
Then depending on the current use, either invoke the normal foo() or the foo_ref() if you want the array to be modified in place.
There is also a common array(&$wrap) parameter cheat, but that doesn't seem suitable in your case. A more contemporary workaround would be this tricky trick:
// pass by value
foo($array);
// pass by reference (implicitly due to being an object)
foo($array = new ArrayObject($array));
This allows for similar reference passing to unprepared functions. Personally I would prefer keeping the E_DEPRECATED warning and the intended syntax for this purpose.
Related
$el = array_shift($instance->find(..))
The above code somehow reports the strict standards warning, but this will not:
function get_arr(){
return array(1, 2);
}
$el = array_shift(get_arr());
So when will it report the warning anyway?
Consider the following code:
error_reporting(E_STRICT);
class test {
function test_arr(&$a) {
var_dump($a);
}
function get_arr() {
return array(1, 2);
}
}
$t = new test;
$t->test_arr($t->get_arr());
This will generate the following output:
Strict Standards: Only variables should be passed by reference in `test.php` on line 14
array(2) {
[0]=>
int(1)
[1]=>
int(2)
}
The reason? The test::get_arr() method is not a variable and under strict mode this will generate a warning. This behavior is extremely non-intuitive as the get_arr() method returns an array value.
To get around this error in strict mode, either change the signature of the method so it doesn't use a reference:
function test_arr($a) {
var_dump($a);
}
Since you can't change the signature of array_shift you can also use an intermediate variable:
$inter = get_arr();
$el = array_shift($inter);
$instance->find() returns a reference to a variable.
You get the report when you are trying to use this reference as an argument to a function, without storing it in a variable first.
This helps preventing memory leaks and will probably become an error in the next PHP versions.
Your second code block would throw an error if it wrote like (note the & in the function signature):
function &get_arr(){
return array(1, 2);
}
$el = array_shift(get_arr());
So a quick (and not so nice) fix would be:
$el = array_shift($tmp = $instance->find(..));
Basically, you do an assignment to a temporary variable first and send the variable as an argument.
The cause of the error is the use of the internal PHP programming data structures function, array_shift() [php.net/end].
The function takes an array as a parameter. Although an ampersand is indicated in the prototype of array_shift() in the manual", there isn't any cautionary documentation following in the extended definition of that function, nor is there any apparent explanation that the parameter is in fact passed by reference.
Perhaps this is /understood/. I did not understand, however, so it was difficult for me to detect the cause of the error.
Reproduce code:
function get_arr()
{
return array(1, 2);
}
$array = get_arr();
$el = array_shift($array);
This code:
$monthly_index = array_shift(unpack('H*', date('m/Y')));
Need to be changed into:
$date_time = date('m/Y');
$unpack = unpack('H*', $date_time);
array_shift($unpack);
The second snippet doesn't work either and that's why.
array_shift is a modifier function, that changes its argument. Therefore it expects its parameter to be a reference, and you cannot reference something that is not a variable. See Rasmus' explanations here: Strict standards: Only variables should be passed by reference
Well, in obvious cases like that, you can always tell PHP to suppress messages by using "#" in front of the function.
$monthly_index = #array_shift(unpack('H*', date('m/Y')));
It may not be one of the best programming practices to suppress all errors this way, but in certain cases (like this one) it comes handy and is acceptable.
As result, I am sure your friend 'system administrator' will be pleased with a less polluted error.log.
$el = array_shift($instance->find(..))
The above code somehow reports the strict standards warning, but this will not:
function get_arr(){
return array(1, 2);
}
$el = array_shift(get_arr());
So when will it report the warning anyway?
Consider the following code:
error_reporting(E_STRICT);
class test {
function test_arr(&$a) {
var_dump($a);
}
function get_arr() {
return array(1, 2);
}
}
$t = new test;
$t->test_arr($t->get_arr());
This will generate the following output:
Strict Standards: Only variables should be passed by reference in `test.php` on line 14
array(2) {
[0]=>
int(1)
[1]=>
int(2)
}
The reason? The test::get_arr() method is not a variable and under strict mode this will generate a warning. This behavior is extremely non-intuitive as the get_arr() method returns an array value.
To get around this error in strict mode, either change the signature of the method so it doesn't use a reference:
function test_arr($a) {
var_dump($a);
}
Since you can't change the signature of array_shift you can also use an intermediate variable:
$inter = get_arr();
$el = array_shift($inter);
$instance->find() returns a reference to a variable.
You get the report when you are trying to use this reference as an argument to a function, without storing it in a variable first.
This helps preventing memory leaks and will probably become an error in the next PHP versions.
Your second code block would throw an error if it wrote like (note the & in the function signature):
function &get_arr(){
return array(1, 2);
}
$el = array_shift(get_arr());
So a quick (and not so nice) fix would be:
$el = array_shift($tmp = $instance->find(..));
Basically, you do an assignment to a temporary variable first and send the variable as an argument.
The cause of the error is the use of the internal PHP programming data structures function, array_shift() [php.net/end].
The function takes an array as a parameter. Although an ampersand is indicated in the prototype of array_shift() in the manual", there isn't any cautionary documentation following in the extended definition of that function, nor is there any apparent explanation that the parameter is in fact passed by reference.
Perhaps this is /understood/. I did not understand, however, so it was difficult for me to detect the cause of the error.
Reproduce code:
function get_arr()
{
return array(1, 2);
}
$array = get_arr();
$el = array_shift($array);
This code:
$monthly_index = array_shift(unpack('H*', date('m/Y')));
Need to be changed into:
$date_time = date('m/Y');
$unpack = unpack('H*', $date_time);
array_shift($unpack);
The second snippet doesn't work either and that's why.
array_shift is a modifier function, that changes its argument. Therefore it expects its parameter to be a reference, and you cannot reference something that is not a variable. See Rasmus' explanations here: Strict standards: Only variables should be passed by reference
Well, in obvious cases like that, you can always tell PHP to suppress messages by using "#" in front of the function.
$monthly_index = #array_shift(unpack('H*', date('m/Y')));
It may not be one of the best programming practices to suppress all errors this way, but in certain cases (like this one) it comes handy and is acceptable.
As result, I am sure your friend 'system administrator' will be pleased with a less polluted error.log.
$el = array_shift($instance->find(..))
The above code somehow reports the strict standards warning, but this will not:
function get_arr(){
return array(1, 2);
}
$el = array_shift(get_arr());
So when will it report the warning anyway?
Consider the following code:
error_reporting(E_STRICT);
class test {
function test_arr(&$a) {
var_dump($a);
}
function get_arr() {
return array(1, 2);
}
}
$t = new test;
$t->test_arr($t->get_arr());
This will generate the following output:
Strict Standards: Only variables should be passed by reference in `test.php` on line 14
array(2) {
[0]=>
int(1)
[1]=>
int(2)
}
The reason? The test::get_arr() method is not a variable and under strict mode this will generate a warning. This behavior is extremely non-intuitive as the get_arr() method returns an array value.
To get around this error in strict mode, either change the signature of the method so it doesn't use a reference:
function test_arr($a) {
var_dump($a);
}
Since you can't change the signature of array_shift you can also use an intermediate variable:
$inter = get_arr();
$el = array_shift($inter);
$instance->find() returns a reference to a variable.
You get the report when you are trying to use this reference as an argument to a function, without storing it in a variable first.
This helps preventing memory leaks and will probably become an error in the next PHP versions.
Your second code block would throw an error if it wrote like (note the & in the function signature):
function &get_arr(){
return array(1, 2);
}
$el = array_shift(get_arr());
So a quick (and not so nice) fix would be:
$el = array_shift($tmp = $instance->find(..));
Basically, you do an assignment to a temporary variable first and send the variable as an argument.
The cause of the error is the use of the internal PHP programming data structures function, array_shift() [php.net/end].
The function takes an array as a parameter. Although an ampersand is indicated in the prototype of array_shift() in the manual", there isn't any cautionary documentation following in the extended definition of that function, nor is there any apparent explanation that the parameter is in fact passed by reference.
Perhaps this is /understood/. I did not understand, however, so it was difficult for me to detect the cause of the error.
Reproduce code:
function get_arr()
{
return array(1, 2);
}
$array = get_arr();
$el = array_shift($array);
This code:
$monthly_index = array_shift(unpack('H*', date('m/Y')));
Need to be changed into:
$date_time = date('m/Y');
$unpack = unpack('H*', $date_time);
array_shift($unpack);
The second snippet doesn't work either and that's why.
array_shift is a modifier function, that changes its argument. Therefore it expects its parameter to be a reference, and you cannot reference something that is not a variable. See Rasmus' explanations here: Strict standards: Only variables should be passed by reference
Well, in obvious cases like that, you can always tell PHP to suppress messages by using "#" in front of the function.
$monthly_index = #array_shift(unpack('H*', date('m/Y')));
It may not be one of the best programming practices to suppress all errors this way, but in certain cases (like this one) it comes handy and is acceptable.
As result, I am sure your friend 'system administrator' will be pleased with a less polluted error.log.
$el = array_shift($instance->find(..))
The above code somehow reports the strict standards warning, but this will not:
function get_arr(){
return array(1, 2);
}
$el = array_shift(get_arr());
So when will it report the warning anyway?
Consider the following code:
error_reporting(E_STRICT);
class test {
function test_arr(&$a) {
var_dump($a);
}
function get_arr() {
return array(1, 2);
}
}
$t = new test;
$t->test_arr($t->get_arr());
This will generate the following output:
Strict Standards: Only variables should be passed by reference in `test.php` on line 14
array(2) {
[0]=>
int(1)
[1]=>
int(2)
}
The reason? The test::get_arr() method is not a variable and under strict mode this will generate a warning. This behavior is extremely non-intuitive as the get_arr() method returns an array value.
To get around this error in strict mode, either change the signature of the method so it doesn't use a reference:
function test_arr($a) {
var_dump($a);
}
Since you can't change the signature of array_shift you can also use an intermediate variable:
$inter = get_arr();
$el = array_shift($inter);
$instance->find() returns a reference to a variable.
You get the report when you are trying to use this reference as an argument to a function, without storing it in a variable first.
This helps preventing memory leaks and will probably become an error in the next PHP versions.
Your second code block would throw an error if it wrote like (note the & in the function signature):
function &get_arr(){
return array(1, 2);
}
$el = array_shift(get_arr());
So a quick (and not so nice) fix would be:
$el = array_shift($tmp = $instance->find(..));
Basically, you do an assignment to a temporary variable first and send the variable as an argument.
The cause of the error is the use of the internal PHP programming data structures function, array_shift() [php.net/end].
The function takes an array as a parameter. Although an ampersand is indicated in the prototype of array_shift() in the manual", there isn't any cautionary documentation following in the extended definition of that function, nor is there any apparent explanation that the parameter is in fact passed by reference.
Perhaps this is /understood/. I did not understand, however, so it was difficult for me to detect the cause of the error.
Reproduce code:
function get_arr()
{
return array(1, 2);
}
$array = get_arr();
$el = array_shift($array);
This code:
$monthly_index = array_shift(unpack('H*', date('m/Y')));
Need to be changed into:
$date_time = date('m/Y');
$unpack = unpack('H*', $date_time);
array_shift($unpack);
The second snippet doesn't work either and that's why.
array_shift is a modifier function, that changes its argument. Therefore it expects its parameter to be a reference, and you cannot reference something that is not a variable. See Rasmus' explanations here: Strict standards: Only variables should be passed by reference
Well, in obvious cases like that, you can always tell PHP to suppress messages by using "#" in front of the function.
$monthly_index = #array_shift(unpack('H*', date('m/Y')));
It may not be one of the best programming practices to suppress all errors this way, but in certain cases (like this one) it comes handy and is acceptable.
As result, I am sure your friend 'system administrator' will be pleased with a less polluted error.log.
I've tested the following and it works on both PHP 5.2 and 5.3, however, it's not documented anywhere as far as I can see so I'm evaluating its use.
I have a function in a class called isValid, this checks a hash to see if the given value is in the set of allowed values. There are some values that are valid, but deprecated; I'd like my isValid function to update the passed in value to the current one and return true.
That's fine for when I call it myself, however, I'd like to use this method when used as a callback for array_filter too.
Here's a test case, which as expected results in an array with the values 2,3,4,5,6.
<?php
$test = array(1, 2, 3, 4, 5);
echo print_r(array_filter($test, 'maptest'), true);
function maptest(&$value)
{
$value ++;
return true;
}
So StackOverflow: is this allowed, or is it undocumented functionality that may disappear/stop working/cause errors in the future?
Yes, it's allowed.
In this respect, there's nothing special about calling functions through callbacks.
However, your specific example does not illustrate one difficulty. Consider:
function inc(&$i) { $i++; }
$n = 0;
// Warning: Parameter 1 to inc() expected to be a reference, value given:
call_user_func('inc', $n);
The problem is that you're passing $n to call_user_func and call_user_func doesn't accept values by reference. So by the time inc is called, it won't receive a reference. This isn't a problem with array_filter because it traverses the array directly and can directly pass the variables in the array to the callback function.
You could use call-time pass-by-reference, but this is deprecated and removed from trunk:
function inc(&$i) { $i++; }
$n = 0;
// Deprecated: Call-time pass-by-reference has been deprecated
call_user_func('inc', &$n);
So the best option is to use call_user_func_array instead:
function inc(&$i) { $i++; }
$n = 0;
call_user_func_array('inc', array(&$n));
This function will pass-by-reference the elements that have the is_ref flag set and will pass-by-value the other ones.
Except when explicitly noted, I'd say this is fine and acceptable. A callback can be any built-in or user-defined function.