类变量范围问题,交叉数据污染

时间:2011-06-08 17:43:06

标签: php class design-patterns scope

所以我有一个调用另一个单例类的主类,但是当运行多个线程(或并发线程)时,我会遇到交叉数据污染。这是一个非常简单的版本来解释这个问题。所有变量setter / getter都在Singleton中,由主类调用和设置。

class A {

    public function doSomething($var) {
        Singleton::instance()->setVar($var);
    }

    public function showSomething() {
        return Singleton::instance()->getVar();
    }

}

// Singleton

class Singleton {
    private static $instance = null;
    private $var;

    public static function instance() {
        if(!isset(self::$instance)) {
            $c = __CLASS__;
            self::$instance = new $c;
        }
        return self::$instance;
    }

    public function setVar($var) {
        $this->var = $var;
    }

    public function getVar() {
        return $this->var;
    }
}

测试脚本1:

$actions = Array(
    'one',
    'two',
    'three',
);

foreach($actions as $act) {
    $action = new A();
    $action->doSomething($act);
    echo "Action: ".$action->showSomething()."\n";
    sleep(2);
}

测试脚本1输出将具有;

one
two
three

测试脚本2:

$actions = Array(
    '1',
    '2',
    '3',
);

foreach($actions as $act) {
    $action = new A();
    $action->doSomething($act);
    echo "Action: ".$action->showSomething()."\n";
    sleep(2);
}

测试脚本2输出将具有;

1
2
3
one
two
three

(不按此顺序,可能缺少其中一个值)

那么为什么在同时执行两个脚本时,测试2中包含测试1?

我是如何测试的:

打开两个终端,在每个终端执行一个脚本(因此睡眠),这样我就可以看到数据污染了。

2 个答案:

答案 0 :(得分:3)

您在问题中写道,test1和test2是两个独立的进程。从您给出的示例代码中我看不出两个脚本以允许进行跨进程交换的方式交换数据(而不是代码)(例如,通过文件,会话等)。

然而,从症状看,当你执行test2时,也会执行test1。

为了更好地了解正在发生的事情,您可以将代码添加到您的单例类中,以回显它当前所做的事情。例如。设置变量或显示它。然后,您可以跟踪问题发生的原因。你应该快速找出问题所在的根源。

或者,如果你手头有一个带调试器支持的IDE,你也可以通过逐步执行来实现。

class Singleton {
    private static $instance = null;
    private $var;

    public static function instance() {
        if(!isset(self::$instance)) {
            $c = __CLASS__;
            self::$instance = new $c;
        }
        echo 'Singleton Instantiated.',"\n";
        return self::$instance;
    }

    public function setVar($var) {
        echo 'Singleton::setVar(', $var, ').',"\n";
        $this->var = $var;
    }

    public function getVar() {
        echo 'Singleton::getVar(): "', $var, '".',"\n";
        return $this->var;
    }
}

答案 1 :(得分:2)

我有点怀疑,所以我运行了上面的代码, 运行良好

即使在script1和script2的每个实例中有数百个值,在连续循环中运行的script1和script2也不会覆盖其他单个属性。

尝试并重试了10分钟,只是为了完全确定。

OP正在进行他的测试错误或者缺少一个难题。

尽管如此, 单身人士不会在流程之间共享 。当然,正如预期的那样。