I had the bright idea of using a custom error handler which led me down a rabbit hole.
Following code gives (with and without custom error handler): Fatal error: Only variables can be passed by reference
function foo(){
$b=array_pop(array("a","b","c"));
return $b;
}
print_r(foo());
Following code gives (only with a custom error handler): (2048) Only variables should be passed by reference
function foo(){
$a=explode( '/' , 'a/b/c');
$c=array_pop(array_slice($a,-2,1));
return $c;
}
print_r(foo());
The second one worries me since I have a lot of 'compact' code. So, I either ditch the bright idea of using a custom error handler (to improve my logging module) or expand all my code.
Anyone with better ideas? Also, WTF?
UPDATE:
Thanks to the answers I've learnt something about how php does error handling. The confusion of E_ALL not including E_STRICT (php 5) is not cool.
On top of all this, creating your own custom error handler enables E_STRICT by default and thats where problems start.
The moral of the story is to use your own error handler to catch them ALL and use the error constants (E_STRICT, E_USER_WARNING, E_USER_ERROR, etc.) to do your filtering.
As for the 'memory corruption issue' with variable references and certain functions, what can I say? Doubly uncool. I'll (which doesn't mean you should) ignore E_STRICT in my error handler and life goes on.
?> Pass by reference: When variables are passed by reference, use & (ampersand) symbol need to be added before variable argument. For example: function( &$x ). Scope of both global and function variable becomes global as both variables are defined by same reference.
Pass-by-reference means to pass the reference of an argument in the calling function to the corresponding formal parameter of the called function. The called function can modify the value of the argument by using its reference passed in.
Pass by Value: The method parameter values are copied to another variable and then the copied object is passed, that's why it's called pass by value. Pass by Reference: An alias or reference to the actual parameter is passed to the method, that's why it's called pass by reference.
“Passing by value” refers to passing a copy of the value. “Passing by reference” refers to passing the real reference of the variable in memory.
array_pop() tries to change that value which is passed as parameter. Now in your second example this is the return value from array_slice(). In engine terms this is a "temporary value" and such a value can't be passed by references. what you need is a temporary variable:
function foo(){
$a=explode( '/' , 'a/b/c');
$b=array_slice($a,-2,1);
$c=array_pop($b);
return $c;
}
print_r(foo());
Then a reference to $b can be passed to array_pop(). See http://php.net/references for more details on references.
Here is what I get when trying your second php code snippet in php-cli after setting error_reporting to E_ALL | E_STRICT
gparis@techosaure:~/workspace/universcine.com$ php -a
Interactive shell
php > function foo(){
php { $a=explode( '/' , 'a/b/c');
php { $c=array_pop(array_slice($a,-2,1));
php { return $c;
php { }
php > print_r(foo());
PHP Strict standards: Only variables should be passed by reference in php shell code on line 3
PHP Stack trace:
PHP 1. {main}() php shell code:0
PHP 2. foo() php shell code:1
As you can see, it's only strict standards here. And you can easily let your custom error handler ignore them (based on the value you get : 2048 for instance, here).
As of php 5.3, E_ALL does not include E_STRICT, look at this :
php > foreach(array("E_ALL", "E_DEPRECATED", "E_STRICT", "E_NOTICE", "E_PARSE", "E_WARNING") as $const) echo $const . " :\t" . constant($const) ."\t". decbin(constant($const)). "\n";
E_ALL : 30719 111011111111111
E_DEPRECATED : 8192 10000000000000
E_STRICT : 2048 100000000000
E_NOTICE : 8 1000
E_PARSE : 4 100
E_WARNING : 2 10
As of php 5.4, E_ALL
does include E_STRICT
:
E_ALL : 32767 111111111111111
E_DEPRECATED : 8192 10000000000000
E_STRICT : 2048 100000000000
E_NOTICE : 8 1000
E_PARSE : 4 100
E_WARNING : 2 10
It's a memory corruption issue (according to PHP dev team). Just throw in an assignment:
function foo(){
$b = array_pop($arr = array("a","b","c"));
return $b;
}
print_r(foo());
:
function foo(){
$a = explode( '/' , 'a/b/c');
$c = array_pop($arr = array_slice($a,-2,1));
return $c;
}
print_r(foo());
The second produces an E_STRICT. You can handle that differently in your error handler if you wish (if you don't want to change those functions).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With