【问题标题】:PHP DataMapper pattern: My class needs an instance of PDO, I want to wrap it inside a Db classPHP DataMapper 模式:我的类需要一个 PDO 实例,我想将它包装在 Db 类中
【发布时间】:2014-04-02 22:50:34
【问题描述】:

这是我所拥有的:

class Entry
{
    public $id;
    public $name;
    public $seoName;
    public $timeCreated;

    public function someFunction()
    {

    }

}

class EntryMapper
{
    protected $db;

    public function __construct(PDO $db)
    {
        $this->db = $db;
    }

    public function saveEntry(Entry &$entry)
    {
        if($entry->id){
            $sql = "";
    }
    else {
        $sql = "INSERT INTO tbl_entry (name, seo_name, time_created) VALUES (:name, :seo_name, :time_created)";
        $stmt = $this->db->prepare($sql);
        $stmt->bindParam("name", $entry->name);
        $stmt->bindParam("seo_name", $entry->seoName);
        $stmt->bindParam("time_created", $entry->timeCreated);
        $stmt->execute();
        $entry->id = $this->db->lastInsertId();
        }
    }

}

现在,这是我在视图文件中使用它的方式(目前只是测试插入命令):

$entry = new Entry();

$entry->name = "Some Company LLC";
$entry->seoName = "some-company-llc";
$entry->timeCreated = date("Y-m-d H:i:s");

$entryMapper = new EntryMapper(new PDO("mysql:host=....."));
$entryMapper->saveEntry($entry);

我想要这样的 $entryMapper 行:

$entryMapper = new EntryMapper(new Database());

意思是我应该有一个单独的类 Database.php 来建立连接。

我试过了,但是由于我的类 EntryMapper.php 直接需要一个 PDO 实例,所以我遇到了一个错误。我尝试过从 PDO 扩展数据库,但这也会引发错误,指出在 EntryMapper 中没有调用 PDO 构造函数

有什么想法吗?

编辑:如果您看到任何代码耦合或类似的迹象,请告诉我,因为我想学习正确编码。非常感谢!

【问题讨论】:

标签: php oop design-patterns pdo datamapper


【解决方案1】:

这就是我最终解决它的方法(如果出现更好的实现,我肯定会重新编码)。这是此处接受的答案下的解决方案实现:Global or Singleton for database connection?

我的 ConnFactory.php

include('config/config.php');

class ConnFactory
{
    private static $factory;

    public static function getFactory()
    {
        if(!self::$factory){
            self::$factory = new ConnFactory();
            return self::$factory;
        }

    }

    private $db;

public function pdo()
{
    if(!$this->db){
        $options = array(
            PDO::ATTR_PERSISTENT => true,
            PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
            PDO::ATTR_EMULATE_PREPARES => false,
            PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8"
        );
        $this->db = new PDO("mysql:host=".DB_HOST.";port=".DB_PORT.";dbname=".DB_SCHEMA."", DB_USER, DB_PASS, $options);
    }
    return $this->db;
    }

}

在我的视图/html文件中的使用(只是插入功能的测试):

$entry = new Entry();
$entry->name = "Kartonaža ad Gradačac";
$entry->seoName = "kartonaza-ad-gradacac";
$entry->timeCreated = date("Y-m-d H:i:s");

$entryMapper = new EntryMapper(ConnFactory::getFactory()->pdo());
$entryMapper->saveEntry($entry);

【讨论】:

  • 但是,我希望能够为数据库连接调用任何更短的内容,而不是“ConnFactory::getFactory()->pdo()”。如果有人知道如何改进这一点,将不胜感激。
【解决方案2】:

您可以使用工厂模式并在数据库类的函数中创建 PDO 对象。

class Database {
    private const connStr = 'mysql:host=.....';

    public static function createPDODatabase() {
        return new PDO(connStr);
    }
}

因此,您可以将 EntryMapper 构造函数称为:

$entryMapper = new EntryMapper(Database::createPDODatabase());

编辑:如果你想通过实例化数据库对象来做到这一点,你应该在数据库类的构造函数中调用 PDO 构造函数。

class Database extends PDO {
    public function __construct($dbname='db_name', $server='localhost', $username='db_user', $password='db_password') {
        parent::__construct("mysql:host=$server;dbname=$dbname", $username, $password);
        parent::setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
    }
}

然后你可以只实例化数据库对象。

$entryMapper = new EntryMapper(new Database());

【讨论】:

  • 您认为在我的配置文件中包含这个 connStr 是否明智?还是留在这里,但在里面使用配置项?
  • 大部分时候最好使用配置文件。
  • 好的,所以我让它工作了:我没有使用 conn 字符串作为常量,而是直接将它保存在 new PDO() 中,它由我的配置项组成。此外,在返回线上方,它是我的连接选项数组。我会将您的答案标记为已接受,因为您建议使用工厂模式。谢谢!
  • -1:你显然不知道工厂到底是什么。带有更糟糕代码的可怕建议(全局范围、违反 OCP、易受攻击的 PDO 初始化)。我想知道为什么 OP 接受它作为答案。
  • @tereško 你在这里有什么建议?谢谢
猜你喜欢
  • 2023-03-09
  • 2010-11-17
  • 1970-01-01
  • 1970-01-01
  • 2012-03-11
  • 2010-12-07
  • 1970-01-01
  • 1970-01-01
  • 2017-05-01
相关资源
最近更新 更多