PHP如何在扩展类中使用父类对象变量?

4

很抱歉,这似乎是初学者的问题。在扩展类中如何访问父类对象的变量?

class FOO {
  public $foo;
  function __construct() {
    $this->foo = 'string';
  }
}

class Parent {
  public $x;
  function __construct() {
    $this->x = new FOO();
    var_dump($x); // this works
  }
}

class Child extends Parent {
  public $y;
  function __construct() {
    var_dump($this->x); // appears to be NULL all the time
  }
}

如何正确传递 $x 的值或引用?

它是 null,因为你需要在 Child 构造函数中调用父类的 Parent 构造函数 parent::__construct() - Rahil Wazir
3个回答

13
你的Child类有自己的x属性。子类会继承除私有成员外的所有内容,因此所有publicprotected属性/方法都将可用。
你声明了属性x,但直到调用Parent构造函数之前它才被初始化。如果一个子类(在这种情况下是Child)有自己的构造函数,则父构造函数将被覆盖并且不会自动调用。
简而言之:你必须在子类中显式调用父级构造函数:
class Child extends Parent
{
    protected $y = 'Some string';//you can initialize properties here, too
    //ALWAYS use access modifiers
    public function __construct()
    {
        parent::__construct();//explicit call to parent constructor
        var_dump($this->x);
    }
}

请注意:如果父类构造函数需要一个参数,那么子类必须做相同的事情(签名必须匹配)。参数类型应该是兼容的(如果不是,则存在违约),你可能希望将参数传递给父类构造函数,让它也执行其任务。
顺便说一句:创建类需要的新实例的构造函数被认为是不良实践。谷歌:S.O.L.I.D.,特别关注依赖注入Liskov原则,以及类型提示。如果你阅读了这些材料,你就会明白为什么这是编写代码的更好方式。
class Dad
{
    /**
     * @var Foo
     */
    protected $x = null;

    public function __construct(Foo $foo)
    {
        $this->x = $foo;
    }
}
//child
class Son extends Dad
{
    /**
     * @var string
     */
    protected $y = 'Some string';

    public function __construct(Foo $foo)
    {
        parent::__construct($foo);
    }
    public function test()
    {
        $results = array();
        $results[] = '$this->x instanceof Foo ? '.($this->x instanceof Foo ? 'Of course!': 'No');
        $results[] '$this instanceof Son ? '.($this instanceof Son ? 'Yup' : 'No?');
        $results[] '$this instanceof Dad ? '.($this instanceof Dad ? 'Yes!' : 'No?');
        return $results;//methods don't echo, they return...
    }
}
$son = new Son(new Foo());
echo implode(PHP_EOL, $son->test());

这段代码的输出结果将会是:
$this->x instanceof Foo ? Of Course!
$this instanceof Son ? Yup
$this instanceof Dad ? Yes!

这似乎让许多(相对)新手在面向对象编程方面感到困惑,但是子类与其父类属于同一类型。如果您仔细思考一下,这是有道理的。对于外部世界(即处理/使用给定类的实例的代码),只有公共方法是可见的。根据定义,子类继承了所有公共的东西,因此对于外部世界来说,这并不重要。
如果某些代码需要一个Dad实例来做某事,那么一个Son也可以工作,因为所有Dad提供的功能,Son也可以做到。子类唯一要做的就是增加父类已经提供的功能。

4
您需要在子类的构造函数中调用父类的构造函数,它不会自动调用:
class Child extends Parent {
    public $y;
    function __construct() {
       parent::__construct();
       var_dump($this->x); // appears to be NULL all the time
    }
}

3
正确的代码是:
<?php
error_reporting(E_ALL);
class FOO {
  public $foo;
  function __construct() {
    $this->foo = 'string';
  }
}

class Parents {
  public $x;
  function __construct() {
    $this->x = new FOO();
    var_dump($this->x); // fixed $x to $this->x
  }
}

class Child extends Parents {
  public $y;
  function __construct() {
    parent::__construct(); // you need to run Parents contructor
    var_dump($this->x); // appears to be NULL all the time
  }
}

$cl = new Child();

此外,您不能使用Parent作为类名,但我相信您是手写的代码并且没有测试过(在此代码中,我已将Parent类名更改为Parents


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接