【问题标题】:PHP assign value to $thisPHP 为 $this 赋值
【发布时间】:2011-05-01 10:11:58
【问题描述】:

基本上我想要实现的是让对象引用同一类的另一个对象 - 从方法内部。如果以下方法可行,那就完美了:

$this = new self;

但是不能在 php 中重新分配 $this

我当然知道,我可以从方法中返回另一个对象并使用它,所以请不要这么建议。问题是:

如何使$this 成为同一类的另一个对象的克隆?

或者更具体地说,

我希望一个对象恢复到之前保存的特定状态。


编辑:一些可能有用的例子。

假设你有一个 Url 对象,它接受控制器、动作和更多的东西。您将让它获取许多具有相同的链接,例如控制器和操作,但其他属性会有所不同。我用公共参数实例化对象,调用一个方法来保存它的状态,它在输出链接后恢复(IOW 在 __toString 方法之后)。

$defaultPath = Url::factory('controller','action1')->extraParams('status',0)->save();

echo $defaultPath->action('action2'); // this has action2 as action and a status 0 as extra params
echo $defaultPath->extraParams('status',2); // this has action1 as action and 2 as status

另一个用途是我有一个 CRUD 表,我必须将每一列配置为传递给主表对象的对象。通过列后,我在列上启动了一个重置​​方法,所以我可以有如下代码:

    $column->field = 'layouts_id';
    $column->value = $layoutId;
    $dbInput->addColumn($column);

    $column->field = 'pages_id';
    $column->value = $pagesId;
    $dbInput->addColumn($column);

在这两种情况下,我都节省了大量代码和混乱,你不觉得吗?

【问题讨论】:

    标签: php oop this


    【解决方案1】:

    我发现您的意图存在很大问题:

    如果您找到了重新分配 $this 的方法,您如何确保使用您的班级的任何人都知道它的行为方式?虽然我承认,这样做很有趣

    $column->field = 'layouts_id';
    $column->value = $layoutId;
    $dbInput->addColumn($column);
    
    $column->field = 'pages_id';
    $column->value = $pagesId;
    $dbInput->addColumn($column);
    

    如果我需要两次$column,会发生什么?

    $column->field = 'layouts_id';
    $column->value = $layoutId;
    $dbInput->addColumn($column);
    // log my value
    $logger->log($column); // oops, it's empty
    
    ...
    

    你会破坏预期的行为,恕我直言,你的代码很难掌握。


    但是要给出一些关于如何仍然实现上述行为的想法:
    // clone when passing on
    $column->field = 'value_id';
    $column->value = $value;
    $dbInput->addColumn(clone $column);
    
    // manually (re-)create a new object based on an older
    $column->field = 'value_id';
    $column->value = $value;
    $dbInput->addColumn(new Column($column));
    


    否则reset() 方法听起来也是可行的:
    class Column() {
    
        public function reset() {
            $this->field = 'standard field id';
            $this->value = 'standard field value';
        }
    
        public function __construct() {
            $this->reset();
        }
    
    }
    

    这样你就可以这样使用它:

    // manually (re-)create a new object based on an older
    $column->field = 'value_id';
    $column->value = $value;
    $dbInput->addColumn($column);
    $column->reset();
    


    要克服两次指定默认值的问题(未经测试):
    class Column() {
    
        public $field = 'standard field id';
        public $value = 'standard field value';
    
        // keep a static object for resetting
        private static $__blueprint = null;
    
        public function reset() {
            foreach (self :: $__blueprint as $k => $v)
                $this->$k = $v;
        }
    
        public function __construct() {
            if (!isset(self :: $__blueprint))
                self :: $__blueprint = clone $this;
        }
    
    }
    

    【讨论】:

    • 可以在将其传递给 addColumn 方法之前对其进行克隆,或者可以将覆盖设为可选(例如,$dbInput->addColumn($column, TRUE); 不会重置列,这很容易实现。)
    • 但是,这仍然不是人们所期望的。当我使用一个对象时,我想处理它。我不希望不相关类的读取方法清除我的对象。感觉好像你会把你的书借给一个在他读完信后擦掉字母的人。 (而且我不想明确告诉他,他不应该删除它们。正如我所说,这不是你通常会期望的行为)
    • 以反映您的编辑:我不希望在 CRUD 表的初始化中没有额外的步骤,即使它们是有效的(因此,+1)。但是,reset 方法不会保持代码 DRY,您必须在两个地方同步初始值,这只是一个加载错误的定时炸弹。
    • reset() 方法可能是您定义默认值的单点。或者,请参阅我上面的编辑。
    • 回应您的评论,是的,但另一方面,您为每列保存一两行,这不仅难以重新输入,而且可能会被遗忘,导致几乎不明显的错误。此外,列对象没有其他功能,只是作为设置的容器,我也可以使用数组 - 它在功能方面是相同的(在文档方面没有那么多。)
    【解决方案2】:

    我认为你得到的基本上是Flyweight Design Pattern。您不能通过重新映射 $this 来做到这一点,但是您创建对象的方式是可以重复使用它们,而无需不断地构造和破坏它们...

    将其与Object Pool 设计模式相结合,您应该是金子......

    【讨论】:

    • 不,不是这样,但模式确实很有趣,我会记住的。这个问题是不是太模糊了?
    • 嗯,这不是你想要做的什么,但它解决了同样的问题(如果我首先理解你的问题)。使对象便宜且可重复使用。当然,它以不同的方式进行,但它仍然可能适用。 (哦,我什至不会回答“你不能为$this 赋值”的问题,因为其他人已经回答得很好)......
    【解决方案3】:

    如果您的假设示例 $this = new self; 确实有效,则可能是为了有效地将对象重置为干净状态。

    您无法按照您要求的方式实现此目的,但您肯定可以通过编写 reset() 方法将所有属性设置为其初始状态然后调用 __constructor() 方法来相当容易地做到这一点。

    如果您想更进一步并从将成为克隆的对象中克隆该类的另一个实例(根据您问题的最后一部分),那将更加困难。你肯定无法以一种好的方式做到这一点。您可以通过编写一个将要克隆的对象作为参数并通过引用将所有当前对象的属性设置为另一个对象的属性的方法来临时装配它。当然,这只有在所有属性都是公开的情况下才有可能,但您可以尝试一下。不过当然不理想。简单地从任何一个对象之外进行操作要好得多...但是您确实说过不要建议... ;)

    【讨论】:

    • [..] reset() 方法将所有属性设置为其初始状态,然后调用 __constructor() 方法。 reset() 方法中,这并不酷。我没有得到__constructor 部分。
    • $this 永远不应该改变 - PHP 是这样构建的,所以你将在违背 PHP 核心的设计时遇到麻烦。 function reset(){foreach((array)$this as $k=>$v)unset($this->$k);}
    • @Xeoncross,关于方法建议,如果某些字段用值实例化怎么办? class A {public $b = 'c';}
    • 没关系,一切都会被删除。
    【解决方案4】:

    您不能在 PHP 中为 $this 赋值。它将始终包含当前对象,并且无法更改。

    听起来您正在尝试更改对当前类的所有引用以指向不同的类。没有办法做到这一点。

    我能想到的最好的解决方法是在你的类中有一个$copy 成员变量。然后,您可以检查 $copy 是否不为空,并将所有方法传递给该对象。但是,这仍会将您的原始对象留在内存中。

    【讨论】:

      【解决方案5】:

      您的要求在 OOP 中没有意义。 this 变量(或您选择的 OOP 语言中的任何等效变量)应始终指向当前实例,并且永远不应更改。这就是它的设计目的。

      【讨论】:

      • 编辑了问题以反映这种模式可能的、IMO 合理的用途。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-05-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-04-10
      • 1970-01-01
      相关资源
      最近更新 更多