代码之家  ›  专栏  ›  技术社区  ›  JRL

返回对PHP中对象的引用

  •  2
  • JRL  · 技术社区  · 14 年前

    我使用的是php5.2.14和pearlog1.12.3。 最新文档 singleton method in Log.php (Pearlog)声明:

    必须使用 $var=&log::singleton()语法。 前面没有符号和(&) 方法名,您将无法 参考文献;你会得到一份副本。

    但是,这样做会产生以下警告:

    严格注意:只有变量才应该 通过引用分配


    此函数的源是:

    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];
    }
    

    如果我移除并仅使用:

    $var = Log::singleton()
    

    然后我再也没有得到警告。同样,如果我这样做

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

    然后$var==var2的计算结果为true。


    问题 :哪个是正确的:API文档或警告?(如果函数返回一个对象,它是否仍然是一个引用?为什么我需要这个符号?

    3 回复  |  直到 14 年前
        1
  •  10
  •   Jeremy    14 年前

    传递对象的方式在php5中发生了根本性的改变。在php4中,它们总是按值传递的,这意味着返回对象的函数或方法实际上正在传递对象的副本。这导致使用“&”运算符,强制函数通过引用返回对象。在php5中,对象总是通过引用传递。要创建对象的副本,必须使用克隆运算符。

    通过快速查看日志包的源代码,可以看出它与php4保持兼容。我认为你不需要符号。php5将返回对对象的引用。您对“$var==$var2”的测试已经证明该方法返回一个对象,并且该对象是对一个对象的引用。如果它们是一个对象的副本,那么身份比较的结果将是错误的。

        2
  •  4
  •   Adam Byrtek    14 年前

    警告是正确的,API文档已过时,从php5开始通过引用返回对象。

        3
  •  3
  •   Fge    14 年前

    在php 5中,处理引用的方法在php中发生了一些变化。现在,他们希望被调用函数决定通过引用或值返回,而不是通过调用方返回。 但通常PHP可以自己解决这个问题——就像在您的例子中一样,它检测到这两个对象是相同的。

    有关您的e_的更多信息,请严格阅读手册: http://www.php.net/manual/en/language.references.whatdo.php 以及如何实现PEAR功能: http://www.php.net/manual/en/language.references.return.php . (在我看来,梨的大部分已经过时了,Zend框架现在覆盖了梨的大部分。)

    编辑:引用的大型示例:

    error_reporting(E_STRICT);
    ini_set('display_errors', 1);
    
    class Settings
    {
        private static $_instance;
    
        public static function getInstance()
        {
            if(self::$_instance == null)
            {
                self::$_instance = new Settings();
            }
    
            return self::$_instance;
        }
    
        public static function &getInstanceByRef()
        {
            if(self::$_instance == null)
            {
                self::$_instance = new Settings();
            }
    
            return self::$_instance;
        }
    
        private $counter = 0;
    
        private function Settings()
        {
        }
    
        public function getCounter()
        {
            return $this->counter;
        }
    
        public function setCounter($value)
        {
            $this->counter = $value;
        }
    }
    
    $settings1 = Settings::getInstance();
    $settings2 = Settings::getInstance();
    
    echo $settings1->getCounter(); // 0
    echo $settings2->getCounter(); // 0
    
    $settings1->setCounter(42);
    
    echo $settings1->getCounter(); // 42
    echo $settings2->getCounter(); // 42
    
    $settings3 = &Settings::getInstanceByRef(); // ref to private static $_instance !
    $settings4 = &Settings::getInstanceByRef(); // ref to private static $_instance !
    
    echo $settings3->getCounter(); // 42
    echo $settings4->getCounter(); // 42
    
    $settings3 = 5;
    $settings5 = Settings::getInstance();
    echo $settings5; // 5 
    

    如您所见,即使没有引用,getInstance也会作为引用处理。如果要使用引用,调用方和被调用函数都必须标记为引用。

    警告:按引用返回可能会导致难以找到的错误:按引用返回允许我覆盖包含var的私有实例。PHP中的预期行为是$settings3是5,但不是私有静态$_实例;这可能导致非常不可预测的代码。