返回对 PHP 中对象的引用

发布于 2024-09-28 04:43:10 字数 1268 浏览 1 评论 0原文

我正在使用 PHP 5.2.14 和 PearLog 1.12.3。 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];
}

如果我删除 &并使用 just:

$var = Log::singleton()

那么我就不再收到警告了。另外,如果我这样做

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

,那么 $var === var2 的计算结果为 true。


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

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 ?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

乖乖公主 2024-10-05 04:43:10

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

快速查看日志包的源代码后发现它保持了与 PHP4 的兼容性。我认为您不需要&符号。 PHP5 将返回该对象的引用。您对“$var === $var2”的测试已证明该方法返回一个对象,并且该对象是对一个对象的引用。如果它们是对象的副本,则身份比较将评估为 false。

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.

喜爱纠缠 2024-10-05 04:43:10

警告是正确的,API 文档已过时,自 PHP5 起通过引用返回对象。

The warning is correct and the API documentation is outdated, objects are returned by reference since PHP5.

贩梦商人 2024-10-05 04:43:10

在 PHP 5 中,处理引用的方式在 PHP 中发生了一些变化。现在,他们希望被调用函数决定按引用或按值返回,而不是调用者。
但通常 PHP 可以自己解决这个问题 - 就像你的情况一样,它确实检测到这两个是同一个对象。

有关 E_STRICT 的更多信息,请查看手册:http://www. php.net/manual/en/language.references.whatdo.php以及pear函数应该如何实现:http://www.php.net/manual/en/language.references.return.php 。 (在我看来,pear 的大部分部分都已经过时了,zend 框架现在涵盖了 pear 的大部分内容。)

编辑:引用的大型示例:

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,但不是私有静态 $_instance;这可能会导致非常不可预测的代码。

The way to deal with references changed a bit in PHP in PHP 5. Now they want the called function to decide to return by reference or by value, not the caller.
But usually PHP can sort this out by itself - like in your case it does detect that these two are the same object.

For more information about your E_STRICT check out the manual: http://www.php.net/manual/en/language.references.whatdo.php and how the pear function should be implemented: http://www.php.net/manual/en/language.references.return.php . (In my oppinion most parts of pear are outdated, the zend framework covers most of pear now.)

Edit: Large example of references:

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 

As you can see even without refence getInstance is handled as reference. If you want to use references, both the caller and the called function must be marked as reference.

As a warning: return by reference can cause hard to find bugs: Returning by reference allows me to overwrite the private instance holding var. The expected behaviour in PHP would be that $settings3 is 5 but not the private static $_instance; This can result in very unpredictable code.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文