奇怪的PHP行为,Base和Derived类的相同字段名,克隆实例

时间:2016-04-26 14:08:39

标签: php inheritance

很抱歉这个混乱的标题,我找不到更好的标题。 我在PHP / 5.6.14上,我有这段代码:

class Base
{
    private $foo;  <--- NOTE
    public function __construct()
    {
        $this->foo = "base foo";
    }
    public final function getFoo()
    {
        return $this->foo;
    }
}

class Derived extends Base
{
    public $foo;  <--- NOTE
    public function __construct($type)
    {
        parent::__construct();
        $this->foo = "derived foo";
        $this->somethingUndefined = "dynamically declared";  <--- NOTE
    }
}

$base = new Base();
var_dump($base->getFoo());
$derived = new Derived(0);
var_dump($derived->getFoo());
$clonedDerived = clone $derived;  <--- NOTE
var_dump($clonedDerived->getFoo());

运行最后一个getFoo()会给我:

  

PHP注意:未定义属性:在C:.. \ test.php中导出:: $ foo   line * getFoo()在基类*。

中实现的行

如果我将这三个条件放在一起,我会收到通知:

  1. 相同的公共/私人字段名称
  2. 在派生类中有一个或多个动态声明的字段
  3. 处理派生类
  4. 实例的克隆

    删除其中一个或多个会使通知消失。

    这里发生了什么? $foo不是静态的,并且不是未定义的...... 我正在使用自定义error_handler将每个E_ALL变为异常,并且无法真正忽略此...

    修改: 这只是我写的一个重现问题的例子,实际代码有很大不同。我不是试图暴露私人$ foo或其他东西。事实上,Base和Derived是由不同的开发人员创建的,他们为一个字段选择了相同的名称,并且这样做(以及其他两个条件)导致了Notice。我只是想了解为什么,因为AFAIK应该完全没问题。

2 个答案:

答案 0 :(得分:1)

这是预期的行为,private仅表示此类。因此,子类不可见私有属性$foo。将其更改为公开是不可行的,可能会有与您没有看到的相关的警告。报告给您的级别错误。

子类必须至少保持父级的相同可见性。

充其量你可以在子类中私有化,但这不会让你访问相同的$foo

注意与否,当试图强制私有变量成为别的东西时,代码的可读性很差。你期望得到哪个foo?如果您在父级中需要$foo作为默认值,为什么不在其他名称中命名它,只需在子级的get方法中执行if / then。

基本上,当子类中的$foo在父类中是私有的时,它会尝试更改它的值$foo。然后从父级中检索它。正如我最多提到的那样,你不会得到你期望的 self.input_data = tf.placeholder(tf.float32, [None, config.n_steps, config.n_input], name='input') # Tensorflow LSTM cell requires 2x n_hidden length (state & cell) self.initial_state = tf.placeholder(tf.float32, [None, 2*config.n_hidden], name='state') self.targets = tf.placeholder(tf.float32, [None, config.n_classes], name='target') _X = tf.transpose(self.input_data, [1, 0, 2]) # permute n_steps and batch_size _X = tf.reshape(_X, [-1, config.n_input]) # (n_steps*batch_size, n_input) input_cell = rnn_cell.LSTMCell(num_units=config.n_hidden, input_size=3, num_proj=300, forget_bias=1.0) print(input_cell.output_size) inner_cell = rnn_cell.LSTMCell(num_units=config.n_hidden, input_size=300) cells = [input_cell, inner_cell] cell = rnn.rnn_cell.MultiRNNCell(cells) ,这会让代码混乱。

答案 1 :(得分:1)

我认为这是PHP中的一个错误,因为在PHP7中运行该示例不会产生此通知。更重要的是,如果您在var_dump($this)定义中getFoo(),则可以清楚地看到"foo":"Base":private已定义,对象foo的{​​{1}}也已定义, PHP&gt; = 7且PHP&lt; 7.请参阅:https://3v4l.org/Ob9m7

但是,我相信,无论你想用这段代码做什么,你都会采用错误的方式。正如ArtisticPhoenix已经提到的那样。我强烈建议你重新考虑并重新设计你正在做的事情。根据OOP,覆盖私有成员是不可能的。