Skip to content

Implement explicit send-by-ref #2958

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 5 commits into from
Closed

Conversation

nikic
Copy link
Member

@nikic nikic commented Dec 2, 2017

RFC: https://wiki.php.net/rfc/explicit_send_by_ref

Currently, in order to pass an argument by reference, the reference
has to be declared at the definition-site, but not at the call-site:

function byRef(&$ref) {}
byRef($var);

This change adds the ability to specify the by reference pass at
both the definition-site and the call-site:

function byRef(&$ref) {}
byRef(&$var);

Importantly, specifying a reference during the call will generate
an error if the argument is not also declared by-reference at the
declaration site:

function byVal($val) {}
byVal(&$val); // ERROR

This makes it different from the call-time-pass-by-reference
feature in PHP 4. If this feature is used, the reference has to
be declared at both the call- and declaration-site.

Note that it is still possible to not explicitly specify the use
of by-reference passing at the call-site. As such, the following
code remain legal:

function byRef(&$ref) {}
byRef($var);

@nikic nikic added the RFC label Dec 2, 2017
@ghost
Copy link

ghost commented Dec 6, 2017

Sounds like a great idea, however, it seems to me that it would be much more useful if there were an optional way to require this mode, and also an optional way to issue warnings when this flag is not passed.

To avoid creating more "strict modes" for users to think about, what if implicit pass-by-reference was deprecated in strict mode, issuing a warning to users who have enabled warnings?

@Fleshgrinder
Copy link
Contributor

I really like this proposal. @elijah-120 such a change to the strict mode would be possible in PHP 8. I think it's a good idea to think about that. However, that can easily be another RFC.

@nikic
Copy link
Member Author

nikic commented Dec 6, 2017

@elijah-120 I don't like the idea of rolling other, unrelated "strictness" features into the existing strict_types flag. I think the best way to do handle this would be through a separate option in combination with https://wiki.php.net/rfc/namespace_scoped_declares, but that proposal did not seem to be well-received.

@ghost
Copy link

ghost commented Dec 6, 2017

Another possible solution would be to simply deprecate the implicit feature language wide and issuing a warning with PHP 8, remove it in 10-15 years. Warnings are pretty harmless and this one is easy to correct, as opposed to deprecating something like preg_replace /e for which there is no easy fix.

The idea is that users who read the code will not have any idea that their variable is being modified. No doubt this was taken from C++, but in that case, they have both pointers and const in case they wish to do something more declarative.

It is debatable, but some style dialects (ie. google https://google.github.io/styleguide/cppguide.html#Reference_Arguments) forbid the non-const pass by reference.

Lets say you wanted to write a function that returns an additional value to a parameter - you would use a pointer, rather than trick the user with a hidden &, if not careless. PHP is pass reference for objects and copy-on-write for arrays and strings, so valid uses of pass-by-reference are limited to returning extra values and sorting an array.

@ghost
Copy link

ghost commented Dec 6, 2017

I was about to say that a fuction like "sort()" is an exception (as it is void return), but actually php array functions are not consistent about whether they modify in place or have return. For example, a user might write array_change_key_case($array) and think that it changed the case of $array, when really it does nothing. So just because you didn't assign sort($array) doesn't mean it is pass-by-reference. You have to know that.

@prgTW
Copy link

prgTW commented Dec 9, 2017

I like this idea although I was wondering how will this compare against typehints, both in function parameters and return typehints. Am I mistaking or this will look like this:

function &func(int &$var): int

IMHO more reasonable place for & for return typehint would be near the typehint itself:

function func(int &$var): &int

Although when not using typehints the & sign would have to back to it's original place, so I understand the reasons behind the current implementation, but when using typehints it starts to look a bit weird.

@ghost
Copy link

ghost commented Dec 9, 2017

@prgTW Yes, you are mistaken about the examples and the typehints. Check the examples in the p/r desc. My idea was just to add a warning when a variable is passed by reference but not using & at call time, but no new syntax from the proposal above.

@nikic nikic force-pushed the explicitPassByRef branch 2 times, most recently from 858c374 to 9128867 Compare July 25, 2019 12:40
@nikic nikic force-pushed the explicitPassByRef branch from 9128867 to 223dd72 Compare February 19, 2020 16:01
Currently, in order to pass an argument by reference, the reference
has to be declared at the definition-site, but not at the call-site:

    function byRef(&$ref) {}
    byRef($var);

This change adds the ability to specify the by reference pass at
*both* the definition-site and the call-site:

    function byRef(&$ref) {}
    byRef(&$var);

Importantly, specifying a reference during the call will generate
an error if the argument is not also declared by-reference at the
declaration site:

    function byVal($val) {}
    byVal(&$val); // ERROR

This makes it different from the call-time-pass-by-reference
feature in PHP 4. If this feature is used, the reference has to
be declared at both the call- *and* declaration-site.

Note that it is still possible to not explicitly specify the use
of by-reference passing at the call-site. As such, the following
code remain legal:

    function byRef(&$ref) {}
    byRef($var);
This is a placeholder for a mode in which & annotations are required.
Swap the numbers for the PREFER_REF and PREFER_VAL passing modes
to make the SHOULD_BE_SENT_BY_REF check more efficient.
@nikic nikic force-pushed the explicitPassByRef branch from f0696e4 to 6814a7a Compare June 11, 2020 16:46
@SailorMax
Copy link

Today we already have PHP 8 beta1!
Any chance to got this change in release?

@Girgias
Copy link
Member

Girgias commented Aug 7, 2020

Today we already have PHP 8 beta1!
Any chance to got this change in release?

No.

@iluuu1994
Copy link
Member

@nikic Is it ok to close this PR and the associated RFC?

@nikic
Copy link
Member Author

nikic commented Jan 25, 2022

Yeah, don't plan any immediate work here.

@nikic nikic closed this Jan 25, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants