【问题标题】:PHP Factory Class Inheritance IssuePHP工厂类继承问题
【发布时间】:2015-03-06 12:05:46
【问题描述】:

我在自己的工厂类上工作,它实例化依赖项并在设置/请求依赖项时传递构造。如果依赖项被缓存(已被另一个类实例化),我将传递该类实例而不是重新实例化(主要用于数据库连接)。我目前遇到的问题如下。

** 为避免出现大问题并节省阅读时间,我试图尽可能简单地说明问题,如果需要实际代码,我可以粘贴。

Class View {
    // Construct Requests User Model
}

Class Controller {
    // Construct Requests User Model & Class View
    $this->user->set($newuserid);
    $this->view->display('file');
}

所以Controller 被实例化,因为View 被设置为依赖项,它被实例化并通过__construct 传递给Controller。一切都很好,但对于个人资料页面之类的东西。在我设置新用户的地方(如上图所示),设置新用户 ID 也会更改包含在 View 用户模型中的用户 ID。我没有使用静态变量,所以我很困惑为什么在controller 中所做的更改会影响view 用户模型。这给我带来了一个问题,因为登录的用户 ID 是通过站点的入口点(引导程序)设置的,并且当配置文件页面覆盖登录的用户 ID 时会导致错误。我在我的工厂中添加了一个newInstance 选项,而是为用户配置文件实例化一个新的用户模型。一切正常,但我仍然很好奇我为什么遇到/遇到这个问题。

【问题讨论】:

  • 我不确定您要问的问题是什么。您可以发布用户模型类并添加评论,这种意外更改发生在哪里?

标签: php factory


【解决方案1】:

在 PHP5 中,保存对象的变量不包含实际对象本身,而是引用实际对象的标识符。

因此,当您传递对象时,实际上是将标识符的副本传递给对象,该对象当然指向同一个对象。

PHP Docs on Objects and references

因此,当您在控制器和视图中使用相同的用户对象并对其进行操作时,实际的用户对象将被更改。由于两个对象变量仍然持有相同的对象标识符,因此对象状态在控制器和视图中将是相同的。

<?php

class User {

    protected $name;

    public function __construct($name)
    {
        $this->setName($name);
    }

    public function getName()
    {
        return $this->name;
    }

    public function setName($name)
    {
        $this->name = $name;
    }

}

class View {

    protected $user;

    public function __construct( User $user )
    {
        $this->user = $user;
    }

    public function render()
    {
        echo $this->user->getName();
        $this->user->setName('Tony');
    }

}

class Controller {

    protected $user;
    protected $view;

    public function __construct( User $user, View $view )
    {
        $this->user = $user;
        $this->view = $view;
    }

    public function someAction()
    {
        $this->user->setName('Thomas');
        $this->view->render();
        echo $this->user->getName();
    }

}

$user = new User('Jeffrey');
$view = new View($user);
$controller = new Controller($user, $view);

$controller->someAction(); // Output: ThomasTony

要理解的关键是,View 和 Controller 都引用同一个对象,因此在一个类中操作对象将导致在另一个类中也对其进行操作(从技术上讲,这是错误的,因为两者都指向同一个对象)。


现在让我们在 View 中使用 clone 关键字:

public function __construct( User $user )
{
    $this->user = clone $user;
}

现在视图的$user 属性将保存一个指向用户对象副本的“指针”。对该对象所做的更改不会影响传递的初始对象。

因此输出将是:JeffreyThomas

我想说几句谨慎的话:

  • 与其克隆对象,不如确保对象的流动方式干净。一旦通过,您的视图不应操纵用户的状态。
  • 使用克隆可能会导致不良行为。如果有人将一个对象传递给您的一个类,并希望类改变对象状态(我们在这里不是在谈论“视图”),而实际上并没有,这会给他们带来非常困难的调试时间。

【讨论】:

  • 我认为 var 拥有自己的对象实例,谢谢您的帮助。我不克隆类,我只是传递它们并分配您在视图示例中所做的方式。为了解决这个问题,我应该将用户模型的新实例传递给配置文件控制器吗?该视图不会更改用户模型,它会请求用户 ID 来确定用户是否已登录,如果是,则使用已登录的用户信息创建一个画布外菜单。像配置文件这样的页面,我使用用户模型来确定正在查看的配置文件,数据由控制器更改视图中的用户 ID 来更改。
猜你喜欢
  • 2023-04-08
  • 2011-10-11
  • 2013-09-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多