在我的项目中,我想构建对多个数据库引擎的支持。我通过放置在模型层中的数据映射器来实现这一点。一个简单的例子看起来像(对不起代码墙,如果你想了解要点,请跳到最后):
用户
namespace Application\Model;
use Application\Model\Mapper;
class User
{
private $mapper;
private $id;
public function __construct(Mapper $mapper, $id)
{
$this->mapper = $mapper;
}
public function setPassword($password)
{
$this->mapper->updatePassword($this->id, $password);
}
}
映射器接口
namespace Application\Model;
interface UserMapper
{
public function updatePassword($id, $password);
}
MySQL 映射器
namespace Application\Model;
use Application\Model\Mapper;
class UserMysqlMapper implements Mapper
{
private $connection;
public function __construct(\PDO $connection)
{
$this->connection = $connection;
}
public function updatePassword($id, $password)
{
$stmt = $this->connection->prepare('UPDATE user SET password = :password WHERE userid = :userid');
$stmt->execute(['password' => $password, 'userid' => $id]);
}
}
PostgreSQL 映射器
namespace Application\Model;
use Application\Model\Mapper;
class UserPgsqlMapper implements Mapper
{
private $connection;
public function __construct(\PDO $connection)
{
$this->connection = $connection;
}
public function updatePassword($id, $password)
{
$stmt = $this->connection->prepare('UPDATE user SET password = :password WHERE userid = :userid');
$stmt->execute(['password' => $password, 'userid' => $id]);
}
}
加载东西
$connection = new \PDO(dsn stuff);
$mapper = \Application\Model\UserPgsqlMapper($connection);
$user = \Application\Model\User($mapper, 1);
$user->setPassword('new password');
如您所见,我有两个基本上带有重复代码的映射器(两个引擎的查询相同)。这有点“强奸” DRY 原则,但是我只是看不到防止这种情况的好/干净/正确的方法。请注意,这当然只是一个简单的示例,通常在不同的数据库引擎中会有不同的查询。
我曾考虑让映射器使用基本查询扩展一些映射器,但这感觉更脏,因为根本不可能有某事的基本查询。
我昨天也在 PHP 聊天中问过这个问题,结论基本上是“伪造重复并继续你的生活”,我越想越觉得这是我唯一真正的选择。
但为了确保我没有错过一些干净而聪明的解决方案,我想我会在这里发布一个问题。