我正在开发一个基于依赖注入的PHP框架。我的数据对象是可注射的组件,与其他任何组件一样。
我有一个抽象的DAO类,每个模型都应该扩展,它有:
简而言之,就像这样
abstract class AbstractDao {
protected $fields;
protected $container; // This is the (injected) DI container, used to create instances.
protected $driver; // The injected database driver (i.e. PDO)
public function insert() {
// Insert implementation
// Insert current instance.
}
public function fetch($id) {
// Fetch implementation
// Fetches a row and sets fields on current instance
}
public function fetchAll() {
// Performs a select * query on database driver
// Iterates through results, and creates an instance
// for each result using $container, like this:
foreach ($results as $row) {
// I can't just make $instances[] = new Something(), or all the
// dependency injection thing would mess up.
$instances[] = $this->container->get('someDao');
}
return $instances;
}
// Other methods.
}
class Book extends AbstractDao {
protected $fields = array('field', 'definition', 'goes', 'here',);
// No special behaviour is needed, so we can keep default
// abstract implementation without overriding.
}
我的问题:每个数据对象实现(一本书,一个人,一个用户等)都必须扩展我的AbstractDao对象,因此它将带有$ driver和$ container的权重。此外,由于$ fields属性是在实例级别定义的,因此每个数据对象都有自己的属性,从而增加了更多的开销。
我担心在处理大数据集时,就性能而言,这种解决方案可能会导致成本过高。我知道对象只会被引用,而不是克隆,但开销可能会高得惊人。
我想到的几个解决方案是
我不喜欢那些解决方案......首先我不喜欢使用静态的东西,因为它们与注射的整个想法有点冲突。其次,我不喜欢删除dao子类模式的想法。
非常感谢任何好主意,谢谢。
===编辑===
我想到的还有一件事。在第二种方法(“dao provider”)中我不喜欢的是提供者必须对Dao字段(设置值,设置状态,设置isDirty等)执行操作,因此必须从外部访问字段。使用子类化方法,可以保护那些受保护的或私有的。
=== / EDIT ===
答案 0 :(得分:2)
我建议您创建一个DAO接口,声明DAO实现必须定义的行为。现在,在每个具体的DAO实现中,您可以定义$driver
,$container
和$fields
实例字段。
之后,您可能希望创建一个AbstractModel
类,每个具体模型都应该扩展,以便您的AbstractModel
和具体模型都将“数据访问不可知”。 AbstractModel
课程最终会如下所示:
/*
* an AbstractModel
*/
abstract class AbstractModel {
protected $daoImpl;
function __construct(DAOInterface $daoImpl) {
$this->daoImpl = $daoImpl;
}
//some other functions that are common to concrete models
}
/*
* a concrete model
*/
class Model extends AbstractModel {
function findAll($params) {
//You can use the $daoImpl of AbstractModel to perform a CRUD operation
$this->daoImpl->findAll($params);
}
}
现在,无论何时实例化具体模型,都会将DAO实现注入模型类。
//inject a DAOInterface implementation into Model
$model = new Model(new DAOImpl());
$model->findAll($params);
这里的优点是你可以在测试期间存根不同的DAO实现,也许这就是DI容器派上用场的地方。我在几天前创建DI容器时创建了similar code sample。
BTW我不认为需要在AbstractDAO中放置一个$container
对象,为什么不传入调用容器属性时返回的对象。这样你就可以使用type hinting来强制对象参数属于某种类型,并且如果传入了错误的对象,则会鼓励快速失败的机制,你也可能会发现创建一个Config类来处理你的$driver
详细信息,以便用户可以自由配置他们想要用于db的驱动程序。