【问题标题】:PHP abstract class does not affect the child of its childPHP 抽象类不影响其子级的子级
【发布时间】:2014-05-16 03:58:36
【问题描述】:

我有一个抽象类,它声明了它的子类所需的方法。它还有一个由其子代继承的委托人。如何使抽象类影响扩展它的类的子类。为了进一步澄清我的问题,这是我的情况:

抽象类(abstract.php):

<?php
include_once 'database.php';
include_once 'validation.php';

abstract class DataOperations extends DatabaseConnection {
  //The error string shared by all children of DataOperations
  //This will be the message to be displayed in case validation failure
  public $validator;
  public $err_valid_string;
  /**
  * The DataOperations' constructor ensures that all of its children can perform database operation
  * by automatically starting it for them. In case a child overrides this constructor, this child
  * must explicitly start the connection to prevent fatal errors. Also, $validator must be re-instantiated
  */
  public function __construct() {
    $this->startDBConnection();
    $this->validator = new InputValidator();
  }
  public function __destruct() {
  }

  abstract public function validateData();
  abstract public function loadRecord($key, $cascade);
  abstract public function saveRecord();
  abstract public function updateRecord();
  abstract public function deleteRecord();
}
?>

现在,这是扩展 DataOperations 抽象类的子对象

class Guest extends DataOperations {
  //some properties here

  public function validateData() {
    //implementation
  }

  public function newRecord(implementation) {
    //implementation
  }

  public function loadRecord($key, $cascade){
    //implementation
  }

  public function saveRecord() {
    //implementation
  }

  public function updateRecord() {
    //implementation
  }

  public function deleteRecord() {
    //implementation
  }
}
?>

这是另一个类,它是 Guest 的子类

class Booking extends Guest {
  //some properties here

  public function validateData() {
    //implementation
  }

  public function newRecord(implementation) {
    //implementation
  }

  public function loadRecord($key, $cascade){
    //implementation
  }

  public function saveRecord() {
    //implementation
  }

  public function updateRecord() {
    //implementation
  }

  public function deleteRecord() {
    //implementation
  }
}
?>

问题是,如果我在 Booking 中删除一个方法,比如 deleteRecord(),PHP 不会抛出错误,因为我认为抽象类不会影响它的“孙子”。我怎样才能解决这个问题?我想过使用接口,但我的系统已经有 11 个类,它们依赖于抽象类的某些方法。这将需要密集的重构。

【问题讨论】:

  • 如果去掉Booking中的deleteRecord,它会继承自Guest,所以满足了实现deleteRecord的条件。根据您的情况,您可能希望使 Guest 成为抽象类。但是接口可能是要走的路

标签: php class parent abstract


【解决方案1】:

正如您自己所说,界面是最适合的解决方案。喜欢

include_once 'database.php';
include_once 'validation.php';

interface DbInterface {
  abstract public function validateData();
  abstract public function loadRecord($key, $cascade);
  abstract public function saveRecord();
  abstract public function updateRecord();
  abstract public function deleteRecord();
}

class DataOperations extends DatabaseConnection {
  //The error string shared by all children of DataOperations
  //This will be the message to be displayed in case validation failure
  public $validator;
  public $err_valid_string;
  /**
  * The DataOperations' constructor ensures that all of its children can perform database operation
  * by automatically starting it for them. In case a child overrides this constructor, this child
  * must explicitly start the connection to prevent fatal errors. Also, $validator must be re-instantiated
  */
  public function __construct() {
    $this->startDBConnection();
    $this->validator = new InputValidator();
  }
  public function __destruct() {
  }

}

class Guest extends DataOperations implements DbInterface {
    - - -
}

class Booking extends Guest implements DbInterface {
    - - -
}

首先,如您所见,我从父类中删除了抽象,因为我假设只有那些方法是抽象的。其次,根据您的 11 个类依赖于抽象类的问题,我想说因为您只删除抽象方法,实现抽象方法的类现在应该实现接口。这是一次需要的任务。而使用抽象类的其他普通方法的类像以前一样工作。

【讨论】:

  • 当我说这将是一次密集的重构时,我想我只是有点偏执,因为我的老板最终希望得到结果。我现在使用一个名为 DataOperations 的接口,用于通过一个名为 Backbone(愚蠢的名字)的类连接到 DatabaseConnection 的所有 11 个类。它不需要太多工作,因为我保留了旧 DataOperations 的方法并将其放到 Backbone。 Tnx
  • 所以要明确一点,当我说抽象类的“抽象性”不会影响它的子孙时,我说得对吗?
  • 实际上GrantParent抽象类(Let A)的抽象方法必须在子类(Let B)中实现,或者子类本身必须定义为抽象。现在,扩展 GrantParent A 的子 B 的 GrandChild 类(Let C)已经实现了方法,因为它的父 B 已经实现了这些方法。一旦 B 不实施这些方法。 GrantChild C 对实现这些方法有同样的限制。
【解决方案2】:

最好和最简洁的方法是让您的“BOOKING”类扩展“DATAOPERATIONS”类,而不是 GUEST,因为看起来您在 BOOKING 类中没有任何额外的方法。其他明智的制作和接口并实现它。这不是首选方式,但您必须提供更多信息。

【讨论】:

  • 是的,我确实考虑了您所说的,但是 Guest 的操作与 Booking 类似,它们也有类似的属性,而且当您在酒店“预订”时,您可能会很快成为“客人”......无论如何,tnx 的帮助
【解决方案3】:

需要明确的是,在子类中重新声明方法将在从子类调用时覆盖父类对该方法的实现,同时不会影响通过扩展父类提供的任何附加功能:

class a 
{
    function hello()
    {
        echo "Hello";
    }

    function goodbye()
    {
        echo "Goodbye";
    }
}

/**
 * class b overwrites class a's implementation of method goodbye but will retain
 * it's definition for method hello
 */
class b extends a
{
    function goodbye()
    {
        echo "See ya!";
    }
}

$object = new b();
$object->hello();  // Hello
$object->goodbye();// See ya!

您似乎希望跨多个类定义实现一致的接口。如果是这种情况,您可能希望使用 PHP 的接口进行探索。

这些允许您指定类定义中必须存在的方法及其参数集(统称为签名)。你的类定义将implement一个接口,如果你的定义不符合接口实现规范,就会抛出一个致命错误。

来自 PHP 手册:

// Declare the interface 'iTemplate'
interface iTemplate
{
    public function setVariable($name, $var);
    public function getHtml($template);
}

// Implement the interface
// This will work
class Template implements iTemplate
{
    private $vars = array();

    public function setVariable($name, $var)
    {
        $this->vars[$name] = $var;
    }

    public function getHtml($template)
    {
        foreach($this->vars as $name => $value) {
        $template = str_replace('{' . $name . '}', $value, $template);
    }

    return $template;
}


// This will not work
// Fatal error: Class BadTemplate contains 1 abstract methods
// and must therefore be declared abstract (iTemplate::getHtml)
class BadTemplate implements iTemplate
{
    private $vars = array();

    public function setVariable($name, $var)
    {
        $this->vars[$name] = $var;
    }
}

您可以在 PHP 手册中找到更多关于接口的信息:

http://us2.php.net/interface

最后,您似乎希望为子类定义一个公共构造函数。您的子类可以在实现单独的接口的同时扩展 DataOperations 类:

class Guest extends DataOperations implements DatabaseWriter
...

【讨论】:

    猜你喜欢
    • 2018-08-23
    • 1970-01-01
    • 2012-02-05
    • 2019-08-02
    • 1970-01-01
    • 1970-01-01
    • 2016-08-12
    • 2017-06-22
    • 2018-07-26
    相关资源
    最近更新 更多