3

I've used both methods quite a bit but I recently wondered why I hadn't standardized on one or the other, or if there was a best practice and what the reasons behind it are.

While the returning references page at PHP states quite clearly, with respect to returning references:

Only return references when you have a valid technical reason to do so.

...the passing by reference page isn't as clear when talking about parameters and return methods.

Consider the following two examples:

Referenced return

class foo {
    public static function bar(&$val) {
        $val++;
    }
}

$input = 0;
foo::bar($input);
echo $input;  // outputs 1

Explicit return

class foo {
    public static function bar($val) {
        $val++;
        return $val;
    }
}

$input = 0;
$input = foo::bar($input);
echo $input;  // outputs 1

Both methods perform the same task and return the same value, but they accomplish it in only slightly different ways. I know that this scenario (multiple solutions to same task) is common in PHP, but my question is...

Is one of the above two methods preferred over the other and if so why?


I should point out that I did see other questions like this one: What's the difference between passing by reference vs. passing by value? but they deal with effects and examples, not why one is preferred over the other.


EDIT: To save any others the hassle of reading through the long discussion regarding the merits of the question...

I was hoping for something specific when taking into consideration the overhead or optimizations inherent in the underlying code whether that be PHP or C, and how that effect would translate to performance after being converted to OpCode and put in the context of potentially thousands of app servers. Small optimizations can have a big effect on the bottom line at the end of the month.

I didn't expect the reluctance, but my guess is that at first glance there isn't a difference when you're considering basic programming requirements. Ours is a different circumstance and so I should have been even more specific up front.

If anyone else cares to weigh in, I'm all ears.

Community
  • 1
  • 1
oucil
  • 4,211
  • 2
  • 37
  • 53
  • possible duplicate of [php return or reference?](http://stackoverflow.com/questions/9513126/php-return-or-reference) – deceze Mar 28 '14 at 13:28
  • @deceze Like the other question I referenced in the edit, it deals with effect, not reasoning. I'm specifically looking for a best practice and valid reasoning why. I've read every one of the answers, and not one provides a concrete reason for one or the other, and there is no reference to best practices. Can you please remove the close request accordingly. – oucil Mar 28 '14 at 13:31
  • @deceze Come on man, this isn't the same question, nor did the others get the answer I'm specifically looking for, or bother to put any work into the question. Cut me some slack and let me get the answer I'm looking for. – oucil Mar 28 '14 at 13:50
  • I think the answer in the dupe is perfectly in line. It's your decision on *API design*. Some methods make sense to accept and modify parameters by reference, others make a lot more sense to return values. What do you think is insufficient about this explanation? – deceze Mar 28 '14 at 14:03
  • @deceze Your answer in the referenced question only speaks to convenience, it doesn't provide any references with regard to intended use cases, performance questions, or the implications of choosing one or the other in a variety of scenarios. Where does it state that one way is for modifying, while the other is for deriving? It's really just an opinion which the OP happened to accept as it related to his question. Like you say, it's a question of API design, but I want to know the implications of it in a more complete way. – oucil Mar 28 '14 at 14:15
  • I don't feel like any particular answer would satisfy you. The answer is *it depends*, *you decide based on the situation what fits better*. There are any number of rules of thumb and examples given. – deceze Mar 28 '14 at 14:34
  • @deceze You're probably right, I don't believe that it's simply preference, or that there isn't a decidedly better way of doing things. If I were to ask the same question in a C++ forum, I'm positive I'd get a definitive answer. The fact that the PHP docs reference performance and internal optimizations as a reason not to use references for functions, but doesn't go into any detail with regard to reference parameters just leads me to believe it's incomplete, not that there isn't a set of guiding principals for best practice. What are those principals? No offense, but you don't answer that. – oucil Mar 28 '14 at 14:42
  • C is a different beast from PHP. In C it has a lot more to do with optimisation in terms of passing pointers or values around and such. In PHP you don't even have such deep access to memory. Passing by reference is really mostly a behaviour modification tool, not an optimisation tool. PHP optimises use of memory and such itself behind the scenes, references have basically no influence on it. Therefore the use of references almost exclusively depends on whether you want to pass by reference or not, what you want your API to work like. – deceze Mar 28 '14 at 14:50
  • @deceze That goes without saying, but seeing as PHP is both written in C and working it's way slowly towards parity with regard to OOP implementations, I think also goes without saying that adhering to those tenets will give you the most forward compatible code, capable of extracting the most out of the language as it evolves and further takes advantage of the underlying optimizations. If I was writing a "Hello world" app, I wouldn't care, but at a million+ lines, the little things begin to matter more. – oucil Mar 28 '14 at 15:01
  • So, you're hoping for an answer considering as of yet unimplemented optimisations which may in the future lead to faster/better code, completely ignoring the aspect of different behaviour and API design right now? Sorry, not going there. Today the decision is based on what you want your API to work like. Period. End of story. Suit yourself. - If anything I find it more likely that future PHP optimisations will be based on popular code usage, not the other way around. – deceze Mar 28 '14 at 15:04
  • @deceze I said that it would take advantage of those underlying optimizations (that you pointed out only exist in C), that means both today and tomorrow. Whatever, you clearly have no interest in the bigger picture, thanks for your input. – oucil Mar 28 '14 at 15:16
  • PHP *is not* C. Whether optimisations exist in C or not, PHP is not C. PHP doesn't have pointers. References in PHP are not the same thing as in C. PHP is a language independent of C, it's merely implemented in C. PHP has its own optimisations according to its own rules, whatever C does is pretty much irrelevant. – deceze Mar 28 '14 at 15:18
  • @deceze That's a little shortsighted. PHP's symbol table implementations benefit from optimizations in C, so while PHP is not C, and while references are not pointers, they benefit from those optimizations at a lower level. Further, when the PHP code is interpreted into opcode, it most certainly benefits from those optimizations at runtime. There are better ways to do things, period. – oucil Mar 28 '14 at 16:00
  • As I said, you're not going to be satisfied by any answer. You are trying to fit any response into your own preconceived notion of what you want to hear; but I'm going to repeat that I will always first and foremost consider *what I want my API to look like and hence what I want my code to look like.* – deceze Mar 28 '14 at 16:10
  • @deceze Just because you personally don't believe that it's important to consider these factors, because you either haven't been exposed to them, or simply don't care, doesn't mean that they're not important. When you consider that a minor change in a single request might only equate to a few CPU cycles, when scaled up to millions of requests, it could mean a difference of several thousand dollars a month in app server instance costs. But like you said, `suit yourself`. – oucil Mar 28 '14 at 16:39

2 Answers2

1

In regards to references in PHP, these are some issues to be aware of:

  • PHP uses copy-on-write to handle an assignment, and so $b = $a will not write $b to a different variable container until there is a change that brings the two variables to differ. One type of change that can occur is that a reference to $b is made by another variable such as $c = &$b (in order for it to be a reference, it now has to copy $b). In C++ a reference does not have its own memory address, and is considered an alias that is-the-object-itself (even though in certain circumstances you can still have dangling references). In PHP, references "... are not like C pointers [pointers - not C++ references]; for instance, you cannot perform pointer arithmetic using them, they are not actual memory addresses, and so on." Given the above information, we see that copying a variable does not take extra memory until a change is made. References in PHP, in some circumstances will add to memory. This happens when $b = $a and $c = &$b (unlike $c = &$a), since even though $b has not changed from $a, it needs its own reference tracking mechanism within a separate zval variable container for $b, and therefore triggers a write for $b.

  • Differences between current and legacy versions of PHP can lead to different handling: "In PHP 4 objects are treated like other variables so when using them as function parameters or doing assignments they are copied. In PHP 5 they are always passed by reference."

  • Languages, human or computer, normally tend toward simplification where possible (unless there is a benefit for complexity that outweighs simplicity):

    • It is more difficult to track referenced changes coming out of a function / method (since there is no way, without looking at the function / method, to see which parameters are passing out as referenced).
    • It is more difficult to keep track of changes involving underlying references.
    • Core functionality sometimes handles differently for references.
      • For instance: $b = &a; unset($b); does not unset $a, but is used to disassociate $b from $a (in this case $b is unset, $a retains its value).
      • For instance: array_filter() does not work with passed references.
  • Unexpected Results:

    • Code like the following does not work as you would expect:
    $array1 = array(1,2);
    $x = &$array1[1];   // Unused reference
    $array2 = $array1;  // reference now also applies to $array2 !
    $array2[1]=22;      // (changing [0] will not affect $array1)
    print_r($array1);

Produces:
Array (
    [0] => 1
    [1] => 22    // var_dump() will show the & here
) 
0

As already said, it's up to you. In my mind, the explicit return is always the best way, so if you come back to your code in 6months you won't ask yourself how that $input var is incremented !

It's indeed easy to find out what a code does when it makes 10 lines, but not when you're working on a more complexe application.

Indeed you need to write a little more code in the explicit return but it is much more readable and the developper which will come after you will understand easily what you did, which is very very important for the maintainability of your application.

Tyrael
  • 123
  • 1
  • 6
  • With regard to ease of understanding, that's only true if you mix and match, if you standardize your principals for going one way or the other, it's easy, there are only two choices, not to mention code hinting. I'm looking for a common set of principals in an OOP sense... "it's up to you" is rarely true, there's almost always a best way of doing something, PHP just makes it too easy to allow for "it's up to you". Inconsistency is the only real enemy of code understanding. – oucil Mar 28 '14 at 14:50