Req #70278 [Opn]: Allow null to be passed by reference
| From: | cyslider at posteo dot de | Date: | Tue, 12 Mar 2019 09:04:44 +0000 |
| Subject: | Req #70278 [Opn]: Allow null to be passed by reference | ||
| References: | 1 | Groups: | php.bugs |
| Request: | Send a blank email to php-bugs+get-219922@lists.php.net to get a copy of this message | ||
Edit report at https://bugs.php.net/bug.php?id=70278&edit=1
ID: 70278
User updated by: cyslider at posteo dot de
Reported by: cyslider at posteo dot de
Summary: Allow null to be passed by reference
Status: Open
Type: Feature/Change Request
Package: *General Issues
PHP Version: Next Major Version
Block user comment: N
Private report: N
New Comment:
> there is no reason for the first line to begin with at all
Tell this my IDE that warns me of an undefined variable which is, at least in eclipse, not
suppressible.
But far more annoying is that I have to remember this as I always initially pass null and get that
error, then have to go back and correct it.
The extra line is less of an issue to me.
Is it really that hard, to allow null at the point where this error is generated, at least if the
default value allows null? Is there a reason not to always allow null, even?
>> 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!
exec is part of PHP core. So consider this advice of rowan collins followed :-)
Previous Comments:
------------------------------------------------------------------------
[2019-03-11 18:19:15] spam2 at rhsoft dot net
> $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);
?>
------------------------------------------------------------------------
[2019-03-11 18:14:07] cyslider at posteo dot de
> I think this case - a parameter which is by-reference, defaultable, and not at the end of the
> list - would be relatively rare, though.
Well I just again came across this using exec
$null = null
exec($script, $null, $result)
So I would still be glad to be allowed to simply pass null in such cases.
------------------------------------------------------------------------
[2015-08-19 00:40:25] requinix@php.net
Related To: Bug #70296
------------------------------------------------------------------------
[2015-08-17 17:59:50] rowan dot collins at gmail dot com
> 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!
------------------------------------------------------------------------
[2015-08-16 14:26:23] cyslider at posteo dot de
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....
------------------------------------------------------------------------
The remainder of the comments for this report are too long. To view
the rest of the comments, please view the bug report online at
https://bugs.php.net/bug.php?id=70278
--
Edit this bug report at https://bugs.php.net/bug.php?id=70278&edit=1