php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Doc Bug #48937 Strict standards: Only variables should be passed by reference
Submitted: 2009-07-16 00:47 UTC Modified: 2009-07-17 22:58 UTC
From: software at whatsonyourbrain dot com Assigned:
Status: Closed Package: Documentation problem
PHP Version: 5.3.0 OS: Win XP SP3
Private report: No CVE-ID:
 [2009-07-16 00:47 UTC] software at whatsonyourbrain dot com
Description:
------------
Using PHP Strict Error Reporting, per Development-mode recommendation, I encounter a so-called "pass-by-reference" error, yet such a construct exists neither explicitly, nor apparently in my code. The Strict Standards Error occurs using the INI directive "error_reporting = E_ALL | E_STRICT". Extended error data shown below is as available through the Xdebug extension "php_xdebug-2.0.5-5.3-vc6.dll", the recommended version for Apache2, win32.

The cause of the error is the use of the internal PHP Programming Data Structures function, end() [ php.net/end ]. The function takes an array as a parameter. Although an ampersand is indicated in the prototype of "end()" in The Manual", there is no 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. 

With the deprecation of call-time pass-by-reference, the pass-by-reference quality of the end() parameter should be indicated in the Manual (in bold-type) to warn programmers that an error WILL occur. 

Reproduce code:
---------------
/*
( ! ) Strict standards: Only variables should be passed by reference in C:\Apache2\htdocs\ww2\class\cwthumbs.class.php on line 15
Call Stack
#	Time	Memory	Function	Location
1	1.1758	371912	{main}( )	..\index.php:0
2	1.1776	449024	require( '..\dochead.inc.php' )	..\index.php:3
3	1.1965	564360	cwThumbs->getThumbs( $dir = 'css' )	..\dochead.inc.php:151 */
// END XDEBUG REPORT
// Line 15:
<?php 
//...
$itemsArray[]= end(explode('/',$item));
//...
?>



Expected result:
----------------
The contents of a container on the filesystem are passed to the function, "end()", as an array.

Actual result:
--------------
The contents of a container on the filesystem are passed to the function, "end()", as an array-- BY REFERENCE-- resulting in a Strict Standards Error, in "Development" mode*.

*"Development" mode: that which is described in php.ini as the recommended setting(s) for use in "Development", "Production", or etc.

Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2009-07-16 00:56 UTC] rasmus@php.net
end() takes the array by reference since it tries to modify the array (by changing the array pointer) and because there is nowhere to store that change you end up with that error. If it only returned the last element, you wouldn't see this warning because it wouldn't need to be passed by reference.
 [2009-07-16 00:58 UTC] rasmus@php.net
I guess we can leave it open as a documentation problem instead.
 [2009-07-16 01:59 UTC] software at whatsonyourbrain dot com
please advise [@16 Jul 12:56am].

(i.e. what is the proper way of coding this procedure, or-- what is the proper way of coding this procedure to avoid error?)
 [2009-07-16 02:56 UTC] rasmus@php.net
Converting to an array doesn't make much sense here.  You are just doing simple string stuff.  I would change it to:

$itemsArray[]= substr(strrchr($item,'/'),1);
 [2009-07-16 13:36 UTC] software at whatsonyourbrain dot com
What is the proper way of coding with end(), for strict standards-- so that its use is not erroneous?

It would seem the instructions provided [@16 Jul 2:56am UTC] are directing the user to avoid use of "end()". Should I assume that "end()" itself will be deprecated?
 [2009-07-16 13:42 UTC] rasmus@php.net
Not at all, simply do:

$parts = explode('/',$item);
$itemsArray[]= end($parts);

If you want to use end() in this case.
 [2009-07-16 14:35 UTC] software at whatsonyourbrain dot com
right. But the reader needs to understand why. The answer: Because, only VARIABLES may be passed by reference, as the error clearly states. 

What is missing here-- for the benefit of others relying upon The Manual for a proper reference-- is a deeper explanation of the reason this error occurs. This is a PHP "type juggling" issue [ http://php.net/manual/de/language.types.type-juggling.php ]

REASON FOR ERROR:
end() is able to extrapolate what TYPE CAST is passed to it, based on the context of the procedure (e.g. a Variable, or an Array). The problem here arises due to passing-by-reference loosely-typed data. To process loosely-typed data w/out error in this instance-- because the data in end() [and other built-in-functions] is Passed-By-Reference, the TYPE must NOT be an ARRAY, but a VARIABLE. Although previous versions of PHP were processing data no matter how the TYPE was CAST, this is no longer the case. When considering what to pass to "end()", no longer may the programmer disregard that data type (i.e. It is important to know when TYPE CASTING data, whether the type cast is an Array, String, Binary, Float, etc., and ALSO precisely HOW a function will handle the data it is passed)

SPECIFICALLY:
In this example, "explode()" returns data of type Array. Versions of PHP pervious to __(?)__ would process data passed to end(), regardless of its TYPE, without error. Since PHP version __?__, Strict Standards require that only Variables are passed by reference. To pass data to end using explode() is incompatible in this instance, due to the TYPE CASTING of explode() as Array. This explains the use of a /temporary/ variable, $parts, in the example provided [@16 Jul 1:42pm UTC].
 [2009-07-16 16:17 UTC] rasmus@php.net
Note that this is not a new thing in 5.3.  This has been the case for a couple of years.  And your explanation is a bit misleading.  You say "the type must not be an array but a variable".  That makes no sense because it is contradictory.  $path = array(1,2,3); end($path);  Here $path is an array and it is, of course, also a variable.

The explanation really is as simple as the warning indicates.  You can only pass variables by reference.  The type of the variable is irrelevant to this.  If you pass something by reference that isn't a variable, then the called function has no place to store its modifications.  It worked in old versions of PHP without a warning, but it actually led to memory corruptions in some cases, so technically this has never worked.
 [2009-07-17 22:58 UTC] rasmus@php.net
Fixed in the documentation in SVN
 
PHP Copyright © 2001-2014 The PHP Group
All rights reserved.
Last updated: Fri Apr 18 13:02:15 2014 UTC