1

我正在使用 Table-Data-Gateway 模式。我所有不是 Mappers 或 DB_Table 类的模型都扩展了 Model_Base。我所有的映射器都扩展了Model_MapperBase. 我所有的 DB_Table 类都扩展了Zend_Db_Table_Abstract.

在我所有的映射器类中,我想强制有一个函数map,它接受一个DB_Row对象,以及映射到的模型类。理想情况下,我希望能够做的是在 my 中Model_MapperBase,我会:

abstract public function map(Model_Base $model, Zend_Db_Table_Row_Abstract $row);

然后当我实现它时,我会这样做:

public function map(Model_User $user, Zend_Db_Table_Row_Abstract $row) {
    $user->setId($row->id)
         ->setName($row->name);
    return $user;
}

但显然,这不起作用,因为抽象函数说它应该采用任何扩展 Model_Base 的类。但我想确保,是的​​,它必须是扩展 Model_Base 之一,但我希望实现更具体

我唯一能想到的就是:

public function map(Model_Base $user, Zend_Db_Table_Row_Abstract $row) {
  if (get_class($user) != 'Model_User') { 
      throw new Exception('Invalid Class');
  } else {
      $user->setId($row->id)
           ->setName($row->name);
      return $user;
  }
}

但这似乎在一定程度上是错误的。有一个更好的方法吗?

编辑:因此,对以下内容不满意,我采取了以下措施:

final public function map(Model_Base $model, 
                          Zend_Db_Table_Row_Abstract $row)
{
    if (get_class($this) != get_class($model).'Mapper') {
        throw new Exception("Invalid Class: Expected " . substr(get_class($this), 0, strlen($this)-6) . '. Received ' .
            get_class($model) . '.');
    }
    return $this->mapImplementation($model, $row);
}

abstract protected function mapImplementation(Model_Base $model, 
                                              Zend_Db_Table_Row_Abstract $row);

然后让我的 Mapper 类实现 mapImplementation 方法,但始终调用 map 方法。这有效地完成了我想要的,但似乎有点做作,并且只是碰巧起作用,因为截至目前,我所有的 Mapper 类都有一个同名的类,没有“映射器”。

有没有更好的方法来完成我想要做的事情,它不依赖于命名方案或在每个类中抛出异常?

编辑:我不是在寻找“使用 instanceOf 而不是 get_class”——这对于我的目的来说本质上是一样的,如果我打算扩展我的非基础映射器类,我会做出改变。我正在寻找一种方法来强制执行正确的类类型,而无需手动抛出异常。

4

3 回答 3

1

由于在扩展抽象类时无法更改方法的标头,我认为您的解决方案很好。

但在我看来,将代码修改为

public function map(Model_Base $user, Zend_Db_Table_Row_Abstract $row) {
if (!$user instanceof Model_User)
  throw new Exception('Invalid Class');

会更好,因为如果您希望在使用类似parent::map(...).

如果classAextendsclassB和是$objectA$objectB的实例,则分别$objectA instanceof classBtruebut get_class($objectA) === 'classA'

于 2013-05-27T08:27:11.823 回答
1

我不知道这有多少收益,但一种方法是像这样在抽象类上创建你的 map 方法

final public function map(Model_Base $user, Zend_Db_Table_Row_Abstract $row) {
    return $this->_map($user, $row);
}

然后为您的用户映射器

public function _map(Model_User $user, Zend_Db_Table_Row_Abstract $row) {
    $user->setId($row->id)
         ->setName($row->name);
    return $user;
}
于 2013-05-30T15:39:35.727 回答
0

PHP 要求方法签名必须相同。

方法的签名必须匹配,即类型提示和所需参数的数量必须相同。

http://php.net/manual/en/language.oop5.abstract.php

这是有道理的,因为您的抽象类正在为使用它的类定义一个契约,并且您正试图在您的实现中更改该契约。天真地,我应该期望能够在Model_Base任何地方将 a 传递给这个函数,并且它应该能够工作。

因此,为了在派生类中强制执行更严格的类型,您需要进行某种类型检查。我更喜欢使用与其他答案相同的方法instanceof。这允许使用该类的扩展而无需修改代码。

于 2013-05-29T16:14:20.540 回答