PDO语句属性存储为对象属性并由对象方法访问

时间:2013-01-07 20:29:58

标签: php pdo

我知道标题并没有提供我所要求的线索,所以这是简化的情况:

class MyPDO extends PDO
{
    private $stmt;

    function __construct($dsn...)
    {
        parent:__construct($dsn...);
    }

    function myQuery($sql)
    {
        $this->stmt = $this->query($query);
    }

    function myFetchAll()
    {
        return $this->stmt->fetchAll($mode);
    }

    function myFetchRow()
    {
        return $this->stmt->fetch();
    }

}

在整个应用程序中,我有一个MyPDO的基本实例,并将其传递给不同的对象,映射器。

$adapter = new MyPDO($dsn...);
$adapter->myQuery('SELECT * FROM table');
$rows = $adapter->myFetchAll();

$another_object = new ObjectThatNeedsPDO($adapter);
$another_object->adapter->myQuery('SELECT * from another_table');
$rows = $another_object->adapter->myFetchAll();

这种方法是否安全,尤其是从MyPDO :: stmt的角度来看?应用程序流程是否会混乱,以便最终从另一个$ stmt中获取数据而不是预期?

3 个答案:

答案 0 :(得分:2)

就个人而言,我不接受你的做法。原因是我不希望一个类创建的语句对象暴露给另一个不相关的类的可能性。此外,每个实现类可能具有需要执行的不同种类的参数绑定,它需要访问数据的方式(即获取所有行,获取每一行,作为对象与数组获取等),方法哪个以特定于类的方式处理错误,等等。

对我而言,通过在基础PDO类的某个孩子中使用这个逻辑,你什么也得不到。我的意思是,这真的很难:

$stmt = $this->pdo->query(...)
$data = $stmt->fetchAll();

比:

$this->myPDO->query(...);
$data = $this->myPDO->myFetchAll();

除了将这个附加类不必要地耦合到将使用它的所有类之外,你还能获得什么?实际上,语句交互总是非常类特定的,实际上是基本PDO实例提供的唯一通用功能(数据库连接)。

因此,当然可以随意在类中传递一个普通的PDO实例,这绝对是一种很好的做法(即依赖注入)。

在您对提议的myPDO类进行更改时,或者是否希望在每次某些实现类需要某些自定义方法与之交互时更改myPDO类时,您是否想要更改每个实现类是非常困难的陈述对象。

根据以下讨论,您似乎可能需要考虑扩展PDOStatement以提供最大的灵活性。

这可能如下所示:

class myPDOFactory {
    public static function getInstance($dsn, $pdo_statement_class = 'myPDOStatement', $pdo_constructor_args = NULL);
        $pdo = new PDO($dsn);
        if (empty($pdo_statement_class)) {
            $pdo_statement_class = 'PDOStatement';
        }
        if (empty($pdo_constructor_args) || !is_array($pdo_constructor_args)) {
            $pdo_constructor_args = array();
        }
        $config_array = array($pdo_statement_class, $pdo_constructor_args);
        $pdo->setAttribute(PDO::ATTR_STATEMENT_CLASS, $config_array);
        return $pdo;
    }
}

class myPDOStatement extends PDO Statement {
    public function __construct(<any custom parameters you may need to have passed - items in $pdo_constructor_args from myPDOFactory class>) {
        parent::__construct();
        // any special stuff you want to do with any passed parameters here
    }

    public function fetchAll() {
        // override any functionality you desire here
    }

    public function fetchAllObjects() {
        return $this->fetchAll(PDO::FETCH_OBJ);
    }
}

class someClassThatNeedsPDO {
    protected $pdo = NULL;
    public function __construct($pdo) {
        if($pdo instanceof PDO) {
            $this->pdo = $pdo;
        } else {
            throw new Exception('Ooops!');
        }
    }

    public function doSomethingWithPDO() {
        $stmt = $this->PDO->prepare('SELECT * FROM sometable');
        $stmt = execute();
        return $stmt->fetchAllObjects();
    }
}

用法示例:

$pdo = myPDOFactory::getInstance($dsn, 'myPDOStatement', $constructor_args);
$consuming_class = new someClassThatNeedsPDO($pdo);
$object_array = $consuming_class->doSomethingWithPDO();  

答案 1 :(得分:1)

你的方法看起来像一个不必要的障碍层,但这应该工作正常。我会在您的fetch方法中添加一个检查,以确保在调用本机fetch / fetchall之前存在有效的PDO语句。

另外,我建议不要为每个MyPDO对象创建新连接。传入PDO连接。

答案 2 :(得分:0)

在处理PDO时(以前使用mysqli包装器),我总是使用单例模式。这意味着您只有一个实例,而不必将其传递给其他类。你正在做的方式是好的和安全的,但使用单身更好。

制作单身人员非常简单:

class myClass{
    private static $instance;

    public static function singleton()
    {
        if (!self::$instance) {
            return self::$instance = new myClass();
        } else {
            return self::$instance;
        }       
    }

    public static function myQuery($query)
    {
        #Do stuff
    }
}

创建实例时,只需调用:

myClass::singleton()

然后如果你想使用这些方法,只需使用:

myClass::myQuery($query)

如果您使用的是名称空间,则需要使用完全限定名称,例如:我的\命名空间\ MyClass的

希望有意义!