Problem/Motivation
According to http://drupaldocs.org/api/head/function/hook_user, the second argument is passed by reference. Several modules were not in compliance.
Proposed resolution
Pass the second argument by reference to hook_user() everywhere in the codebase.
Remaining tasks
RTBC.
User interface changes
None.
API changes
None.
Original report by @Steve Dondley
According to http://drupaldocs.org/api/head/function/hook_user, the second argument is passed by reference. Several modules were not in compliance. This patch fixes this.
| Comment | File | Size | Author |
|---|---|---|---|
| #20 | hook_user-41351-20.patch | 2.28 KB | gnuget |
| #10 | zend.png | 151.08 KB | chx |
| hook_user.patch | 3.88 KB | Steve Dondley |
Comments
Comment #1
Wesley Tanaka commenteddo those modules actually change the value of the parameter?
Comment #2
Steve Dondley commentedWell, I went to create a patch for the contact module and discovered it didn't work because it was not in spec. A spec is a spec and functions should follow it.
Comment #3
killes@www.drop.org commentedI agree with Steve. People (eg me) often use core modules as a sceleton for new contrib modules...
Comment #4
chx commentedArguments are not *passed* but *received* by reference. I know that Zend Studio complains if you use reference in vain. I even read it why but can't remember. I think I even sent in patches to not pass variables by reference unless necessary.
So a very big negative number on this.
Comment #5
Steve Dondley commentedI can't find evidence via Google that zend recommends against using reference "in vain". I should think something like that would be mentioned in this basic document http://de3.php.net/manual/en/language.references.php but could find nothing.
Using reference would seem to help speed things up, if anything, and save a lot of overhead writing data stuctures to and from memory.
Comment #6
Steve Dondley commentedchx, maybe you didn't look at the patch. This patch changes the function definition, not the function call.
Comment #7
Steve Dondley commentedsetting to review. I'd like to open it up to more review before it gets rejected.
Comment #8
Crell commentedIt's a real pity that PHP doesn't have a const &$param argument type...
For the time being, if the spec says it should be passed by reference, then any function that doesn't accept by reference is a bug and should be fixed. If it shouldn't be passed by reference, then the spec should be changed and code updated accordingly. But pick one and be consistent.
Although, doesn't PHP5 change the reference passing system so that arrays are always "by reference", vis, the data is never copied? In that case, by reference or by value wouldn't make any difference, since it becomes by-reference in practice anyway. I suppose in that case sticking with the explicit by-reference is a good thing, as it ensures the same behavior under both PHP4 and PHP5.
(If I'm wrong about PHP5, then ignore only paragraph 3. :-) )
Comment #9
Wesley Tanaka commentedFor what it's worth, I agree with #4 and #8. without being able to pass things "const" by reference, changing this will just make the code that tiny bit much more difficult to read for those that touch drupal code in "Maintenance" mode (for example those that try to fix bugs without being intimate with all the code base).
Perhaps the correct fix is to update the documentation to be more clear.
Comment #10
chx commentedHere's what Zend Studio has to say about this.
Comment #11
Steve Dondley commentedOK, I was being a bit thick on this. I got it now.
Comment #12
chx commentedWhat's the fun here, Zend Studio actually gave us a performance warning on system_user so the opposite of the original patch is needed -- one that REMOVES references instead one that ADDs more.
Comment #13
chx commentedComment #14
Jaza commentedMoving to 6.x-dev queue.
Zend Studio is correct: AFAIK, the PHP interpreter is optimised in such a way that it performs better with by-value parameters than with by-reference parameters. I definitely remember reading somewhere in the PHP manual, something to the effect of: "despite what you think, you should pass variables by value whenever possible, as it's better for performance".
Comment #15
panchoThis way it seems to be a "by design". I still leave it open, as we might change some hook implementations to the opposite (see #12).
Comment #16
dpearcefl commentedIs this issue still needed?
Comment #17
joachim commentedPatch needs a reroll, but would suit a novice: setting to needs work for that.
Really don't see why this has been open for so long; it's a no-brainer: our hook implementations should be consistent for several very good reasons, and Zend is just wrong.
Comment #18
joachim commentedOops, forgot to tag it.
Comment #19
xjmUnassigning so that someone can pick it up for the reroll.
Comment #20
gnugetI re-roll the patch for the 6.x-dev branch.
Comment #21
xjmThat looks fine to me.
This is not an issue in D7 or D8 (since
hook_user()does not exist).Comment #22
gábor hojtsySeems like it was still in debate above without agreement on whether this is the best approach? (I personally would agree following the spec consistently would be best BTW but a little more feedback would be good).
Comment #23
kristen polI read through the history here and see several ways to move forward:
1) Leave the function signatures as is (i.e. no patch) as @chx suggests. This leaves the signatures inconsistent across the codebase (which doesn't sit well with me, but would keep Zend Studio happy). Currently, the signatures in 6.x core are:
a) With reference:
Other consistencies issue are the use of
$typevs.$opand$uservs.$account, but those aren't for this issue.b) Without reference:
which are all addressed in the patch.
2) Leave signatures as is but added a comment to each function as to why (i.e. $edit is not modified in the code).
3) Apply the patch to get signatures in sync.
My preference is for option 3, but, since this issue is over 6 (!) years old, I imagine there are still people who'll have opposing opinions.
Comment #24
gábor hojtsyWho reviewed that none of the functions actually change the values now passed by reference? I did not find explanation of that above (or missed it).
Comment #25
xjmblock_user()explicitly sets$editto an empty array when it is empty, but nothing else:comment_user()andlocale_user()do not use the parameter at all.system_user()uses the parameter to set the form's theme and timezone fields but does not update$edit.Comment #26
thedavidmeister commentedPatch still applies cleanly.
I think the majority of people here are in favour of the DX improvement of using consistent function signatures throughout core over the perceived performance gain of avoiding the references.
I say "perceived" performance gains because nobody has actually done any profiling to demonstrate a measurable difference before and after, we're just going off an 8 year old screenshot from an IDE.
hook_user()is not on a critical performance path, I personally can't imagine any real world scenario where you'd have any kind of performance hit that doesn't fall firmly under the heading of "micro optimisation". I found this stack overflow post that suggests the performance difference is going to be somewhere in the ballpark of 15 micro seconds - http://stackoverflow.com/questions/178328/in-php-5-0-is-passing-by-refer...We see support for honouring the spec and keeping things consistent in #2, #3, #8, #9, #17, #20, #21, #22
All detractors from this proposal reference the 15 microsecond performance hit and nothing else, which doesn't seem like a strong enough reason to deliberately avoid the spec. If it is, we should be modifying the spec first, then revisiting the whole codebase not just
hook_user()in isolation.In #25, @xjm has gone to the effort of confirming that none of the variables newly passed by reference are modified.
This is RTBC for me.