|
php.net | support | documentation | report a bug | advanced search | search howto | statistics | random bug | login |
[2015-08-15 15:06 UTC] cyslider at posteo dot de
Description:
------------
Please allow null - and preferable also any other value - to be directly passed into a function that expects a reference.
If I want to pass 'null' by reference I currently have to do it like this:
function testFunc(Array &$array = null) {
// Do something
}
$null = null;
testFunc($null);
This is cumbersome.
Better would be to also allow:
testFunc(null);
I would suggest some automatical boxing in case a direct value is passed instead of a referenceable variable. That way you could also pass strings directly into a function that expects a reference merely for performance reasons.
function exec (&$sql) {
//Execute SQL
}
exec("Select 1");
Which currently throws an error.
Greetings,
CySlider
PatchesPull RequestsHistoryAllCommentsChangesGit/SVN commits
|
|||||||||||||||||||||||||||
Copyright © 2001-2025 The PHP GroupAll rights reserved. |
Last updated: Tue Oct 28 04:00:01 2025 UTC |
Thanks for the elaborate reply. First of all lets not side track. My request was mainly for the null reference. The other request was just a "nice-to-have" addition. If I declare a function parameter as "Array &$array = null", however you may judge its use, I expect it to be able to accept a direct "null" value. I don't see your other arguments apply to this. Anyhow: > Nearly every function that "expects a reference merely for > performance reasons" has been written wrong - in many > cases, pass by reference actually has worse performance > (the compiler is cleverer than people give it credit > for). The language shouldn't be making such incorrect > usage easier. > There can be cases where you can avoid a copy-on-write > using a reference param, but they should be carefully > considered, and are unlikely to be in frequently-called > code where creating a variable would be burdensome. Ok, I know compilers have some dark magic tricks up their sleves and are awsome in this, but I don't like to rely on some mechnisms that I do not fully understand. Anyhow, what you claim sounds strange, copying faster than passing by reference? So I made a benchmark. function testA(Array &$arr) { return count($arr); } function testB(Array $arr) { return count($arr); } $c = 0; Utils::addTimestamp("Test A: Begin"); for ($i = 0; $i<10000000; $i++) { // Huge array defined in 2000 lines of code. $c += testA(Globals::$structure); } Utils::addTimestamp("Test A: End"); Utils::addTimestamp("Test B: Begin"); for ($i = 0; $i<10000000; $i++) { $c += testB(Globals::$structure); } Utils::addTimestamp("Test B: End"); echo "Elements: ".($c/10000000); Result: [0.0982170105] +0.0035328865: Test A: Begin [6.9941301346] +6.8959131241: Test A: End [6.9941751957] +0.0000450611: Test B: Begin [9.6694211960] +2.6752460003: Test B: End So you were not simply right, its amazing 2-3 times faster than not using a reference!! But to my understanding this can not so much be an intelligent compiler than a massive screwup in the references implementation... In one case it needs to copy a 2000 lines Array and in the other it has only to pass a small reference??!? What am I missing here? > Most of the time, if a function is asking for something by > reference, it should be because it's expecting to write > back to that variable, so passing a non-variable makes no > sense. For this case, the current behaviour is entirely > correct. I personally think in an object oriented language this should be achieved by passing objects instead of directly passing literals as reference. I know this is a leftover of PHP 4 times, but nowerdays, the only reason for me to use "by reference" on literals should be performance. > Note that because your first example provides a default > parameter value, you can just write testFunc(); anyway if > you're not interested in the reference parameter. I know that. This was just a quick example. In my case the parameter in question is in midst of other parameters that need to be specified. The default parameter is just specified, because else its not allowed to pass 'null' at all. Beside that, often this functions are declared in includes so I have no control over how the function is defined. Anyhow, thanks for this yet again unexpected insight about PHP. Guess I have to rethink my strategy reguarding references.... Alot....> If I declare a function parameter as "Array &$array = null", however > you may judge its use, I expect it to be able to accept a direct > "null" value. I don't see your other arguments apply to this. The =null does two things in this example: it relaxes the type-checking of the "array" hint to allow nulls, and it allows you to omit the parameter when you call the function (eliminating the need to pass null at all). There is a case where I can see that it might be useful to pass an explicit null, which is if the function had parameters in an awkward order, e.g. function foo($required, &$optional_output=null, $useful_flags=null) I think this case - a parameter which is by-reference, defaultable, and not at the end of the list - would be relatively rare, though. There has been some discussion of adding a keyword to specify that you want the default value, or a syntax for named parameters, which might fit this use-case better anyway. Allowing null, but not other literals, for *all* reference parameters seems like it might cause confusion; not allowing literals for reference parameters in general is, I believe, a deliberate design decision. > In one case it needs to copy a 2000 lines Array and in the other > it has only to pass a small reference??!? > What am I missing here? You should have a look at an introduction to PHP's Internals, and in particular look up the concept of "copy-on-write". Because count() doesn't need to make any changes to the array, your testB() function doesn't actually need a new copy of the data - nothing else can change the data, so it can just look at the existing copy. So this is exactly what the Zend Engine in PHP does: it creates a reference to the original data internally, and only if you actually change it does it make a full copy of the data. I won't go into the reasons here, but because of how Zend Engine 2 (i.e. PHP 5.x) implements this, passing or assigning by reference sometimes actually defeats this optimisation, forcing the engine to create an unnecessary copy of the data. (Zend Engine 3 / PHP 7.x has a slightly different implementation, I believe.) > I personally think in an object oriented language this should be > achieved by passing objects instead of directly passing literals > as reference. In that case, simply do not use pass-by-reference at all. :) > the only reason for me to use "by reference" on literals should > be performance. As discussed, and as you yourself have seen, this is generally NOT a good reason to use pass-by-reference. The pass-by-reference semantics are there so you can write things like this: function populate_data(&$output) { $output = [1, 2, 'buckle my shoe']; } Here populate_data(null) is clearly an error, since it is equivalent to writing this nonsensical code: null = [1, 2, 'buckle my shoe']; Obviously there are more borderline cases, but in general the requirement that reference parameters be something you can assign back to is a deliberate and useful one. > Beside that, often this functions are declared in includes so > I have no control over how the function is defined. This is certainly true, but that doesn't automatically mean that the language should be changed, rather than just the third-party code you are calling into. File a bug with them if you think their function signatures could be more useful - you'll probably get a faster turnaround than waiting for a new stable version of PHP anyway!> $null = null > exec($script, $null, $result) there is no reason for the first line to begin with at all [harry@srv-rhsoft:/downloads]$ php test.php [harry@srv-rhsoft:/downloads]$ cat test.php <?php declare(strict_types=1); exec('hostname', $null, $result); ?>That is what my IDE shows me. Also a bug? function exec ($command, array &$output = null, &$return_var = null) {} I understand 'array &$output = null' as having null by default. Sorry if this is not meant that way internally. I am not aware of that. I thought this notation always refers to setting a default value in case the value is omitted.