【问题标题】:Session variable in PHP containing object is changed when original object is changed更改原始对象时更改包含对象的 PHP 中的会话变量
【发布时间】:2014-02-19 14:09:12
【问题描述】:

在一些我不允许更改的第三方代码中,发生了一些奇怪的事情。

他们将一个变量(一个包含对象的数组)写入会话(不对其进行序列化),然后在原始变量上使用 foreach 进行迭代(不使用引用)。每当他们更改一个值时,会话中的相应值也会更改。我能够创建一个具有相同行为的较小示例:

$test = array((object)array("categories" => "test"));

$_SESSION['woot'] = $test;

print_r($_SESSION['woot']);

foreach ($test as $a) {

    if (!is_array($a->categories)) $a->categories = array(); 

}

print_r($_SESSION['woot']);

这是结果:

Array
(
    [0] => stdClass Object
        (
            [categories] => test
        )

)
Array
(
    [0] => stdClass Object
        (
            [categories] => Array
                (
                )

        )

)

我已经注意到,当我对对象数组进行序列化和反序列化时,问题不会发生。

有人知道这里发生了什么吗?是代码吗?是不是服务器设置不正确?在联系代码的开发人员之前,我想了解更多信息。

附加信息:

  • 我使用的是 PHP 版本 5.3.14
  • 注册全局变量已关闭

问候, 约斯特。

【问题讨论】:

    标签: php session


    【解决方案1】:

    仅保存对象holds a reference to that object 的变量。将一个对象(对象引用)从一个变量分配给另一个变量不会复制该对象,仍然只有一个对象。如果您修改该对象,所有持有该对象引用的变量都会看到更改,因为只有一个对象实例。

    如果你想复制一个对象,你需要明确地clone它。

    【讨论】:

    • 感谢您的回答。然而米歇尔更早。
    【解决方案2】:

    在 PHP 中对象是 passed by reference,而 PHP 使用 copy-on-write

    $test = array((object)array("categories" => "test"));
    // it is still the same array
    $_SESSION['woot'] = $test;
    foreach ($test as $a) {
        // You change something in an object, which is passed by reference
        if (!is_array($a->categories)) $a->categories = array();
    }
    

    序列化和反序列化创建新对象

    $test = array((object)array("categories" => "test"));
    // new array with new objects
    $test = unserialize(serialize($test));
    

    【讨论】:

    • 我一直认为 foreach 仅在您明确表示应该通过添加 & 时才使用引用。 foreach($a => &$b) 又学到东西了。
    • @jberculo 对于除对象之外的所有变量类型都是如此,其中&$a 是默认行为,与$a 相同。
    • 然而,有一件事。第三方声称他们无法使用相同的代码库重现此问题。是否也有 PHP 版本的组件在工作?
    • @jberculo 这种行为是 PHP 的核心概念。另一方面,正如你所说,你提供了一个小例子,可能还有其他事情在起作用。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-07-20
    • 2016-02-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-19
    相关资源
    最近更新 更多