Search code examples
phpreferenceobjectpearlogging

Returning a reference to an object in PHP


I'm using PHP 5.2.14 and PearLog 1.12.3. The latest documentation from the singleton method in Log.php (PEARLog) states:

You MUST call this method with the $var = &Log::singleton()syntax. Without the ampersand (&) in front of the method name, you will not get a reference; you will get a copy.

However, doing so generates the following warning:

STRICT NOTICE: Only variables should be assigned by reference


The source for this function is:

public static function singleton($handler, $name = '', $ident = '',
                                 $conf = array(), $level = PEAR_LOG_DEBUG)
{
    static $instances;
    if (!isset($instances)) $instances = array();

    $signature = serialize(array($handler, $name, $ident, $conf, $level));
    if (!isset($instances[$signature])) {
        $instances[$signature] = Log::factory($handler, $name, $ident,
                                              $conf, $level);
    }

    return $instances[$signature];
}

If I remove the & and use just:

$var = Log::singleton()

then I no longer get the warning. Also, if I do

$var = Log::singleton();
$var2 = Log::singleton();

then $var === var2 evaluates to true.


Question: Which is correct: the API documentation or the warning? (If the function returns an object, isn't it a reference anyway? Why would I need the ampersand ?


Solution

  • The way that objects are passed fundamentally changed in PHP5. In PHP4 they were always passed by value, meaning that a function or method that returned an object was actually passing a copy of the object back. This led to the use of the '&' operator, forcing the function to return an object by reference. In PHP5 objects are always passed by reference. To create a copy of an object you have to use the clone operator.

    From having a very quick look at the source for the log package it appears that it maintains compatibility with PHP4. I don't think that you need the ampersand. PHP5 will return a reference to the object. Your test of '$var === $var2' has proved that the method returns an object and that the object is a reference to one object. If they were copies of an object the identity comparison would evaluate to false.