【问题标题】:Inheritance not working in PHP继承在 PHP 中不起作用
【发布时间】:2012-07-16 19:48:01
【问题描述】:

我有这个结构:

abstract class Android {
    public function __construct() {

    }

    public abstract function cost();

    public function get_model(){
        return "unkown model";
    }
}

class HTC extends Android {

    public function __construct() {
        parent::__construct();
        $this->model= "HTC";
    }

    public function get_model() {
        return $this->model;
    }

    public function cost() {
        return 500;
    }
}

abstract class FeaturesDecorator extends Android {
    public function __construct() {
        parent::__construct();
    }

    public abstract function get_description();
}

class VideoCamera extends FeaturesDecorator {
    private $android;

    public function __construct($android) {
        parent::__construct();
        $this->android=$android;
    }

    public function get_description() {
         return $this->android->get_model()." plus a video camera, ";
    }

    public function cost() {
        return 200 + $this->android->cost();
    }
}

class BigScreenSize extends FeaturesDecorator {
    private $android;

    public function __construct($android) {
        parent::__construct();
        $this->android=$android;
    }

    public function get_description() {
        return $this->android->get_model()." plus a big size screen, ";  
    }

    public function cost() {
        return 100 + $this->android->cost();
    }
}

应用以下模式后:

$android2 = new HTC();
$android2 = new BigScreenSize($android2);
$android2 = new LongLastingBattery($android2);

echo "<br/><br/>You have bought ".$android2->get_description()." for $".$android2->cost();

我明白了

您以 650 美元的价格购买了 Unkown 品牌和长效电池

再说一遍:

我想知道为什么我从get_model() 调用的get_description() 中得到Unknown brand 而不是HTC$650 正在被正确计算

【问题讨论】:

  • 你应该看看this博客文章。在这种方法中使用abstract class 会导致 PHP 不支持多继承(至少不以这种方式)。此代码需要重构并采用与 abstract class 不同的方法。

标签: php class inheritance abstract


【解决方案1】:

当我第一次测试你的代码时,php 告诉我 LongLastingBattery 类不存在,这是正确的 - 它不存在。我假设你的意思是VideoCamera;所以你在我的回答中的主要功能将从这个开始:

$android2 = new HTC();
$android2 = new BigScreenSize($android2);
$android2 = new VideoCamera($android2);

您的问题是您只是混淆了get_description()get_model() 这两种方法:您首先在 VideoCamera 实例上调用 get_description()。那里有 $this->android->get_model(),其中 $this->android 是 BigScreenSize 的一个实例。 BigScreenSize 类不会覆盖方法 get_model()。 BigScreenSize 扩展了 FeaturesDecorator,它也不会覆盖此方法,而是扩展了具有此方法并返回 "unknown model" 的 Android。

要解决这个问题,您可以在 VideoCamera 和 BigScreenSize 中将 $this-&gt;android-&gt;get_model() 更改为 $this-&gt;android-&gt;get_description(),并将 Android 和 HTC 中的 get_model() 方法重命名为 get_description()。最后,您必须将 FeaturesDecorator 更改为:

abstract class FeaturesDecorator extends Android {}

然后你会得到这个:

<br/><br/>You have bought HTC plus a big size screen,  plus a video camera,  for $800

【讨论】:

    【解决方案2】:

    您的 FeatureDecorator 继承自 Android,而不是 HTC。所以第一次添加装饰时,$android2 将是 Android 类型,而不是之前的 HTC 类型。

    也许你的意思是:

    abstract class FeaturesDecorator extends HTC {
      // ...
    }
    

    这应该为您的示例提供正确的输出。


    编辑您可以将model 成员变量移动到Android 类;应该也可以:

    abstract class Android {
      protected $model = "unknown model";
    
      public function get_model() {
        return $this->model;
      }
    }
    

    这样model 直接存储在Android 中,可以从所有子类中设置,并且可以从任何其他持有Android 对象引用的类中检索。

    【讨论】:

    • 是的,但是 htc 有 Android 抽象类,它有 get_model... 可以被 htc 覆盖..
    • @DmitryMakovetskiyd:是的,它可以被HTC 覆盖,但是你的装饰器不会扩展HTC——它们只会扩展AndroidAndroidFeatureDecorator 都不知道 HTC。您可以做的一件事是将model 成员变量存储在Android 而不是HTC,这也可以。
    【解决方案3】:
    $android1=new HTC();
    $android2=new BigScreenSize($android1);
    $android3=new VideoCamera($android2);
    

    在 $android2 和 3 上执行 var_dump 将为您提供它们持有的对象(必须更改为摄像机,因为您提供的代码中不存在电池类)并且 android3 持有 bigscreensize 对象而不是 htc,因此 '未知'。如果你想获得你的结果('HTC'),你必须(首先让 $android 公开而不是私有)和

    echo $android3->android->get_description();
    

    或根据您的示例(仍然在您的课程中公开 $android)

    echo $android2->android->get_description();
    

    应用这些更改给了我:

    您以 800 美元的价格购买了 HTC 和大尺寸屏幕

    最后,我仍然坚持我最初的想法,即你应该修改你所采取的方法。也许添加一个方法,从它的父级获取 $model 并在构造函数中使用它。这样您就可以跟踪模型并使用本地属性。 (在我上面的示例中,摄像机在执行 get_description() 时尝试访问 bigscreensize->get_model(),此方法在 bigscreensize 中不存在,但在作为 bigscreensize 父级的父级的 android 中存在。继承在这里工作得很好。请注意,您的装饰器不知道 htc 类的存在,因此除非您为所有装饰器提供访问/传递“模型”变量的方法。通过第一个装饰器,您将无法访问它。cost() 有效,因为它存在在每个班级。

    我应该在昨晚回答之前阅读这个问题。对不起。

    【讨论】:

    • 有什么区别。 cost() 方法就是这样工作的,但是 get_description ,,,doesnt..为什么?
    • @DmitryMakovetskiyd 我希望这次我能提供更多帮助。
    猜你喜欢
    • 2017-05-11
    • 1970-01-01
    • 2018-05-24
    • 2015-03-04
    • 2012-06-04
    • 2013-04-24
    • 1970-01-01
    • 1970-01-01
    • 2021-02-26
    相关资源
    最近更新 更多