I have a method in one of my classes that will in some cases be passed an enormous value as a parameter. I was thinking that if this were C++, I might want to pass that parameter by reference to avoid piling it all on the stack:

	public function foo(&$huge_param) {
		// do some stuff blah blah
		return $this->bar();
	}

HOWEVER, the php documentation says:

PHP Docs wrote:

Returning by reference is useful when you want to use a function to find to which variable a reference should be bound. Do not use return-by-reference to increase performance. The engine will automatically optimize this on its own. Only return references when you have a valid technical reason to do so.

I'm thinking I should not be calling by reference to try and speed things up. Is that right?

    From the documentation it sounds like the PHP parser does this optimization for you and it doesn't matter either way. Reference only let's the class/function that you pass to work on the original object. That is all based on my reading of your posted documentation though, so take it at face value. 🙂

      Yeah I think you might be right, but the bit I posted refers to returning values by reference, not sending them as params. That whole section in the docs is a bit much to get my head around. I have noticed that you can't pass a string literal by reference. This causes an error:

      function myfunc(&$var) {
      	trace($var);
      }
      myfunc('string');

      the error:

      Fatal error: Only variables can be passed by reference in /Users/christopherwalsh/Desktop/chump.php on line 6

      That solves it for me for now. No passing by reference in this particular case.

        sneakyimp;10908849 wrote:

        Yeah I think you might be right, but the bit I posted refers to returning values by reference, not sending them as params. That whole section in the docs is a bit much to get my head around. I have noticed that you can't pass a string literal by reference. This causes an error:

        function myfunc(&$var) {
        	trace($var);
        }
        myfunc('string');

        the error:

        Fatal error: Only variables can be passed by reference in /Users/christopherwalsh/Desktop/chump.php on line 6

        That solves it for me for now. No passing by reference in this particular case.

        ]function myfunc(&$var) {
        	trace($var);
        }
        $myvar = 'string';
        myfunc($myvar);
        

        😉

          Thanks Nog, but I have been unable to detect any speed difference between passing args by reference and passing them directly in the profiling I've been doing. I may look into it more later.

            sneakyimp wrote:

            I have a method in one of my classes that will in some cases be passed an enormous value as a parameter. I was thinking that if this were C++, I might want to pass that parameter by reference to avoid piling it all on the stack:

            In PHP 4, a variable that stores an object really stores an object. In PHP 5, a variable that stores an object stores a pointer to the object, without pointer notation (i.e., what the Java and some other people call references). Passing by reference remains the same as in C++. So, assuming that you are familiar with pointers and references, you would know that changing a pointer to point to something else in a function changes only the local pointer, not the pointer in the caller. The same happens in PHP 5 when you assign a new object to a variable in a function; hence if that is your intent, you would pass by reference.

              sneakyimp wrote:

              Thanks Nog, but I have been unable to detect any speed difference between passing args by reference and passing them directly in the profiling I've been doing. I may look into it more later.

              There won't be (unless you do it unnecessarily a lot, in which case the code can be slower because of the extra reference counting involved). Since PHP 4 the Zend engine only copies values if and when it is necessary to do so to maintain the appearance of "pass by value".

              When to pass by reference? When you want whatever happens to the contents of the parameter inside the function to be reflected in the variable containing the corresponding argument after the function has returned.

                Weedpacket wrote:

                When to pass by reference? When you want whatever happens to the contents of the parameter inside the function to be reflected in the variable containing the corresponding argument after the function has returned.

                Yes and no. The problem is that you would only need to pass by reference when you want to assign to the parameter and have that assignment reflected in the caller (changing the object's identity, so to speak). If you only want to call functions that change the object's state, then there is no need to use pass by reference.

                  Thanks so much. You guys seem to be saying the same thing and I think I understand: Only pass by reference when you want the passed argument to be changed at the point in the calling code where the function is called.

                  I have no such intention in my current code - I was merely hoping to speed performance by trying to avoid unnecessary data copying to and from the stack or something. Based on what weedpacket said, this sounds like a bad idea:

                  Weedpacket wrote:

                  Since PHP 4 the Zend engine only copies values if and when it is necessary to do so to maintain the appearance of "pass by value".

                  laserlight, sounds like you are telling me that in PHP5 it is possible to pass an object to a function NOT BY REFERENCE and still make changes to it. Or at least you are trying to make a subtle correction to Weedpacket's post. Perhaps a code example would help?

                    sneakyimp wrote:

                    laserlight, sounds like you are telling me that in PHP5 it is possible to pass an object to a function NOT BY REFERENCE and still make changes to it. Or at least you are trying to make a subtle correction to Weedpacket's post. Perhaps a code example would help?

                    Yes, consider:

                    <?php
                    
                    class X {
                        private $member;
                    
                    function __construct($member) {
                        $this->member = $member;
                    }
                    
                    function get() {
                        return $this->member;
                    }
                    
                    function set($member) {
                        $this->member = $member;
                    }
                    }
                    
                    function foo($x) {
                        $x->set(2);
                    }
                    
                    function bar($x) {
                        $x = new X(3);
                    }
                    
                    function baz(&$x) {
                        $x = new X(4);
                    }
                    
                    $x = new X(1);
                    echo $x->get() . ' ';
                    foo($x);
                    echo $x->get() . ' ';
                    bar($x);
                    echo $x->get() . ' ';
                    baz($x);
                    echo $x->get() . ' ';

                    The expected output in PHP 5 is "1 2 2 4", but in PHP 4 it would be "1 1 1 4".

                      great! thanks for much for that. I feel much edified.

                        laserlight;10908938 wrote:

                        Yes and no. The problem is that you would only need to pass by reference when you want to assign to the parameter and have that assignment reflected in the caller (changing the object's identity, so to speak). If you only want to call functions that change the object's state, then there is no need to use pass by reference.

                        That's what I said. The phrase "contents of the parameter" was not intended to be taken to refer also to the components of the contents of the parameter.

                        Even then, you're thinking specifically of objects, and not, e.g., arrays.

                          PHP5 also provides the [man]clone[/man] operator; which creates a new object, duplicating the state of the existing object, that can be manipulated independently of the original. So passing in a clone in a sense "snaps" the reference.

                          Note that the clone is only a shallow copy: if the original has (a reference to) an object as one of its properties, the clone will typically have a reference to the same object.

                          $obj = (object)array('foo'=>42);
                          
                          $t = (object)array('bar'=>$obj);
                          
                          var_dump($t);
                          
                          $b = clone $t;
                          
                          $b->bar->foo = 17;
                          
                          var_dump($t);
                          
                          $b->bar = (object)array('foo'=>'Fnord');
                          
                          var_dump($t);
                          

                          To be honest, though, I don't find cloning that useful; can't remember the last time I actually used it, in fact. Now that I think about it, some OO languages don't even provide cloning - C#, for example. They recognise that "cloning" is really a matter of constructing a new object from an existing one, and so expect you to write a constructor to do the job.

                            Weedpacket wrote:

                            That's what I said. The phrase "contents of the parameter" was not intended to be taken to refer also to the components of the contents of the parameter.

                            Ah 🙂

                            Weedpacket wrote:

                            To be honest, though, I don't find cloning that useful; can't remember the last time I actually used it, in fact. Now that I think about it, some OO languages don't even provide cloning - C#, for example.

                            I agree. It might have been better to provide a standard interface construct instead and just let it be implemented where necessary.

                            Weedpacket wrote:

                            They recognise that "cloning" is really a matter of constructing a new object from an existing one, and so expect you to write a constructor to do the job.

                            A copy constructor is not quite the same as a clone function since a clone function allows for polymorphism.

                              Write a Reply...