Jump to content

When to use returning by reference?


NotionCommotion

Recommended Posts

Per http://php.net/manual/en/language.references.return.php

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. To return references, use this syntax:

 

 

 

The following four examples are provided in the documentation.  Example 2 makes perfect sense, but not really examples 1, 3, or 4.  Can anyone shed some light on how the returned reference would be used?

<?php
//Example 1. http://php.net/manual/en/language.references.pass.php
function foo(&$var)
{
    $var++;
}
function &bar()
{
    $a = 5;
    return $a;
}
foo(bar());


//Example 2. http://php.net/manual/en/language.references.return.php
class foo {
    public $value = 42;


    public function &getValue() {
        return $this->value;
    }
}
$obj = new foo;
$myValue = &$obj->getValue(); // $myValue is a reference to $obj->value, which is 42.
$obj->value = 2;
echo $myValue;                // prints the new value of $obj->value, i.e. 2.


//Example 3. http://php.net/manual/en/language.references.return.php
function &collector1() {
  static $collection1 = array();
  return $collection1;
}
$collection1 = &collector1();
$collection1[] = 'foo';


//Example 4. http://php.net/manual/en/language.references.return.php
function &collector2() {
  static $collection2 = array();
  return $collection2;
}
array_push(collector2(), 'foo');

 

Link to comment
Share on other sites

Do you have specific questions or just want to understand what they're doing?

 

#1 uses return-by-reference and pass-by-reference. It's just a trivial example to show both happening at once. One without the other and the code wouldn't work.

 

#3 demonstrates a function using a static variable (so that all calls to it use the same variable) and return-by-reference (so that callers can modify the variable directly). Without the reference collector1() would have to provide some way to modify the value, but since it's a local static variable that means fun stuff like

function collector1($key = null, $value = null, $addnull = false) {
	static $collection1 = array();
	if ($value !== null || $addnull) {
		if ($key === null) {
			$collection1[] = $value;
		} else {
			$collection1[$key] = $value;
		}
	}
}
If you can't trust callers to manipulate $collection1 properly then you're forced into something like the above, but if you do can then it's much easier to use a reference.

 

#4 is the same thing but without the temporary $collection1 variable.

Link to comment
Share on other sites

As a somewhat practical example of when you might want to return a reference, say for example you have a largish array tree (maybe something you json_decoded) and want to access it using a dot-separated path. You might have a function that can turn that path into a reference to that part of the tree which you could then manipulate if you wanted to.

 

For example

$config = [
    'doctrine' => [
        'dbal' => [
            'default_connection' => 'default'
            , 'connections' => [
                'default' => [
                    'driver' => "%database_driver%"
                    , 'host' => "%database_host%"
                    , 'port' => "%database_port%"
                    , 'dbname' => "%database_name%"
                    , 'user' => "%database_user%"
                    , 'password' => "%database_password%"
                    , 'charset' => 'UTF8'
                ]
                , 'special' => [
                    'driver' => "%database_driver%"
                    , 'host' => "%database_host%"
                    , 'port' => "%database_port%"
                    , 'dbname' => "%database_name_special%"
                    , 'user' => "%database_user_special%"
                    , 'password' => "%database_password_special%"
                    , 'charset' => 'UTF8'
                ]
            ]
        ]                
        , 'orm' => [
            'default_entity_manager' => 'default'
            , 'auto_generate_proxy_classes' => "%kernel.debug%"
            , 'entity_managers' => [
                'default' => [
                    'connection' => 'default'
                    , 'naming_strategy' => 'doctrine.orm.naming_strategy.underscore'
                    , 'mappings' => [
                        'AppBundle' => [
                            'type' => 'yml'
                            , 'dir' => 'Resources/config/doctrine'
                            , 'alias' => 'AppBundle'
                        ]
                    ]
                ]
            ]
        ]
    ]
    , 'swiftmailer' => [
        'transport' => "%mailer_transport%"
        , 'host' => "%mailer_host%"
        , 'username' => "%mailer_user%"
        , 'password' => "%mailer_password%"
        , 'spool' => ['type' => 'memory' ]
    ]
];


var_dump($config['doctrine']['dbal']['default_connection']);
$connection = &getKey($config, 'doctrine.dbal.default_connection');
$connection = 'special';
var_dump($config['doctrine']['dbal']['default_connection']);

function &getKey(&$config, $path){
    if (strpos($path, '.') !== false){
        list($key, $path) = explode('.', $path, 2);
        return getKey($config[$key], $path);
    } else {
        return $config[$path];
    }
}

Link to comment
Share on other sites

Archived

This topic is now archived and is closed to further replies.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.