Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/oop/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Php 编程范例:带继承的强类型参数_Php_Oop_Design Patterns_Architecture - Fatal编程技术网

Php 编程范例:带继承的强类型参数

Php 编程范例:带继承的强类型参数,php,oop,design-patterns,architecture,Php,Oop,Design Patterns,Architecture,警告:可能导致TL:DR 我使用的是PHP5.3.10,有以下问题。我确实有一个抽象类DataMapper,它是为我想要持久化的特定DataModel而扩展的。以下代码执行此操作: abstract class DataMapper { public abstract function findById($id); public abstract function fetchAll(); public abstract function save(IModel $mode

警告:可能导致TL:DR

我使用的是PHP5.3.10,有以下问题。我确实有一个抽象类
DataMapper
,它是为我想要持久化的特定
DataModel
而扩展的。以下代码执行此操作:

abstract class DataMapper {
    public abstract function findById($id);
    public abstract function fetchAll();
    public abstract function save(IModel $model);               // DISCUSSION
    /* more helper functions here */
}

class PersonMapper extends DataMapper {
    public function findById($id) { /* ...magic ... */ }
    public function fetchAll() { /* ...magic ... */ }
    public function save(IModel $model) { /* ...magic ... */ }  // DISCUSSION
}

interface IModel {
    public function setOptions(array $options);
    public function toArray();
}

abstract class Model implements IModel {
    protected $_fields = array();
    protected $_data = array();

    public function setOptions(array $options) { /* ...magic ... */ }
    public function toArray() { /* ...magic ... */ }

    public function __construct(array $options = null) { /* ...magic ... */ }
    public function __set($name, $value) { /* ...magic ... */ }
    public function __get($name) { /* ...magic ... */ }
}

class PersonModel extends Model {
    protected $_fields = array('id', 'name', 'passhash', /*...*/);

    public function setId($value) {
        /* ...Validation happening... */
        $this->_data['id'] = $value;
        return $this;
    }

    public function checkPassword($password) { /* ...magic... */ }
}
这很好,但对我来说真的很奇怪

如您所见,我使用了一个接口
IModel
来告诉DataMapper,它确实需要一组特定的参数和方法。但是,一些模型确实有相应的数据映射器所需的额外方法-在本例中,是一个
checkPassword()
方法,用于根据存储的哈希值测试密码。此方法还可以指示数据映射器重新刷新刚刚测试的密码,并根据新的要求(例如,密码哈希函数的难度增加)进行更新

因此,我实际想要的是将PersonMapper的签名更改为
PersonMapper::save(PersonModel$model)
——例如,在另一个数据映射器中更改为
PostMapper::save(PostModel$model)
,等等。这是因为这些数据映射器需要特定的签名。因此,我的理想解决方案如下所示:

abstract class DataMapper {
    public abstract function findById($id);
    public abstract function fetchAll();
    public abstract function save(Model $model);                   // UPDATED
}

class PersonMapper extends DataMapper {
    public function findById($id) { /* ...magic... */ }
    public function fetchAll() { /* ...magic... */ }
    public function save(PersonModel $model) { /* ...magic... */ } // UPDATED
}

abstract class Model { /* ...unchanged... */ }

class PersonModel extends Model { /* ...unchanged... */ }
注意抽象类中的更新保存方法及其实现。由于
PersonModel
是从
Model
继承而来的,因此显然有一组共同的基本签名,因此我希望它可以正常工作。但事实并非如此——PHP抱怨childclass PersonMapper中的接口发生了更改

我的问题:

  • 是否有另一种使用PHP5.3.10的解决方案可以更好地表达这种关系
  • 它是否在更高版本的PHP中工作,因此可能值得升级服务器

您可以尝试改用接口

interface OtherModel {
    public function getThis();
}

interface OtherOtherModel {
    public function getThat();
}
您的模型类可能实现一个或多个接口

class PersonModel extends Model implements OtherModel {
    protected $_fields = array('id', 'name', 'passhash', /*...*/);

    public function setId($value) {
        /* ...Validation happening... */
        $this->_data['id'] = $value;
        return $this;
    }

    public function checkPassword($password) { /* ...magic... */ }

    public function getThis() {
        // ...
    }
}
您的具体映射器类可以使用instanceof检查此模型是否执行了它应该执行的操作

class PersonMapper extends DataMapper {
    public function findById($id) { /* ...magic... */ }
    public function fetchAll() { /* ...magic... */ }
    public function save(Model $model) { 
       // verify that certain methods are implemented...
       // throw an exception or reacting accordingly
       print ($model instanceof PersonModel)? 'yes' : 'no';
       print ($model instanceof OtherOtherModel)? 'yes' : 'no';
    } 
}
另一种可能的方法可能是:

<?php

abstract class DataMapper {
    public abstract function findById($id);
    public abstract function fetchAll();

    public  function save(Model $model) {
        throw new Exception('You have to implement this!');
    }
}
我可以想出另一种可能的方法,通过使用接口来定义实现。 例如:

interface PersonModelAware {
   public function save(PersonModel $model);
}

interface OtherModelAware {
   public function save(OtherModel $model);
}
等等。您的抽象方法可能有默认的保存方法,或者根本没有保存方法。继承类将实现它需要的接口


总而言之,使您的类型更具体将无法工作,因为抽象方法清楚地表明它需要一个模型

您可以尝试改用接口

interface OtherModel {
    public function getThis();
}

interface OtherOtherModel {
    public function getThat();
}
您的模型类可能实现一个或多个接口

class PersonModel extends Model implements OtherModel {
    protected $_fields = array('id', 'name', 'passhash', /*...*/);

    public function setId($value) {
        /* ...Validation happening... */
        $this->_data['id'] = $value;
        return $this;
    }

    public function checkPassword($password) { /* ...magic... */ }

    public function getThis() {
        // ...
    }
}
您的具体映射器类可以使用instanceof检查此模型是否执行了它应该执行的操作

class PersonMapper extends DataMapper {
    public function findById($id) { /* ...magic... */ }
    public function fetchAll() { /* ...magic... */ }
    public function save(Model $model) { 
       // verify that certain methods are implemented...
       // throw an exception or reacting accordingly
       print ($model instanceof PersonModel)? 'yes' : 'no';
       print ($model instanceof OtherOtherModel)? 'yes' : 'no';
    } 
}
另一种可能的方法可能是:

<?php

abstract class DataMapper {
    public abstract function findById($id);
    public abstract function fetchAll();

    public  function save(Model $model) {
        throw new Exception('You have to implement this!');
    }
}
我可以想出另一种可能的方法,通过使用接口来定义实现。 例如:

interface PersonModelAware {
   public function save(PersonModel $model);
}

interface OtherModelAware {
   public function save(OtherModel $model);
}
等等。您的抽象方法可能有默认的保存方法,或者根本没有保存方法。继承类将实现它需要的接口


总而言之,使您的类型更具体将无法工作,因为抽象方法清楚地表明它需要一个模型

是的,但我现在的解决方案也可以做到这一点。问题是,是否有可能在方法的签名中而不是在主体中获得需求。如果您只阅读签名,您仍然不知道save函数是否需要PersonModel而不是其他模型,而这正是我试图实现的。@Lars好的。您的方法的问题是您使提示类型更显式,这将不起作用。我可以想出另一种方法,而不是在抽象类中声明抽象save方法,而是创建不同的接口,这些接口包含save(PersonModel$model)等。这是一种有效的方法。我对DataMapper做了一些修改,使其不包含抽象方法,现在实现了默认行为。我不完全理解你的评论的解决方案-你能用一个例子更新你的答案吗?是的,但我现在的解决方案也可以。问题是,是否有可能在方法的签名中而不是在主体中获得需求。如果您只阅读签名,您仍然不知道save函数是否需要PersonModel而不是其他模型,而这正是我试图实现的。@Lars好的。您的方法的问题是您使提示类型更显式,这将不起作用。我可以想出另一种方法,而不是在抽象类中声明抽象save方法,而是创建不同的接口,这些接口包含save(PersonModel$model)等。这是一种有效的方法。我对DataMapper做了一些修改,使其不包含抽象方法,现在实现了默认行为。我不完全理解你的意见的解决方案-你能用一个例子更新你的答案吗?