5

我构建了这个类来使用 PDO,使 SQL 查询“更容易”并且不用担心。

这是我的想法

  • 它应该更像 DB 类扩展 PDO 吗?
  • 查询方法是否太大?是否应该将其拆分为称为的私有方法..这就是所谓的松散耦合吗?
  • 我检测 SELECT 查询的方式是否太丑陋了?
  • 还有哪些明显的问题?由于我是在边学习边学习,我敢肯定我可能会忽略很多潜在的问题。

谢谢

`

 class Db
 {
    private static $_instance = NULL;


    private function __construct() {

        // can not call me
    }

    private function __clone() {

        // no!
    }

    public static function getInstance() {

        if (!self::$_instance)
        {

            try {

                self::$_instance = new PDO('mysql:host=' . CONFIG_MYSQL_SERVER . ';dbname=' . CONFIG_MYSQL_DATABASE, CONFIG_MYSQL_USERNAME, CONFIG_MYSQL_PASSWORD);;
                self::$_instance-> setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

            } catch(PDOException $e) {

                trigger_error($e->getMessage());

            }

        }

        return self::$_instance;


    }



    public static function query($query /*string*/, $bindings = NULL)
    {

        $queryPortion = substr($query,0, 6);

        try {

            if ($bindings) {

                    $prepared = self::getInstance()->prepare($query);

                    foreach($bindings as $binding=>$data) { // defaults to string

                        if (!is_array($data)) {
                            $prepared->bindParam($binding, $data); 

                        } else {

                            switch(count($data)) {

                                case 1:
                                    $prepared->bindParam($binding, $data['value']);
                                    break;                          

                                case 2:
                                    $prepared->bindParam($binding, $data['value'], $data['dataType']);
                                    break;

                                case 3:
                                    $prepared->bindParam($binding, $data['value'], $data['dataType'], (int)$data['length']);
                                    break;                          

                                default:
                                    trigger_error('An error has occured with the prepared statement bindings.');
                                    return false;
                                    break;
                            }
                        }

                    }

                    $prepared->execute();

                    return $prepared->fetchAll(PDO::FETCH_ASSOC);


            } else if (String::match($queryPortion, 'select')) { // if this is a select query

                $rows = self::getInstance()->query($query);

                return $rows->fetchAll(PDO::FETCH_ASSOC);

            } else {

                return self::getInstance()->exec($query);

            }


        } 
        catch(PDOException $e)
        {
            trigger_error($e->getMessage());
        }


    }

    public static function getLastInsertId()
    {
        try {
            self::getInstance()->lastInsertId();
          }
        catch(PDOException $e)
        {
            trigger_error($e->getMessage());
        }

    }

    public static function disconnect()
    {
        // kill PDO object
        self::$_instance = NULL;

    }
 }
4

5 回答 5

5

这还不错,正如人们所说,它可能对小型应用程序有所帮​​助,尽管它主要是对另一个抽象的非常薄的抽象。它没有带来很多其他功能。

除其他事项外,您可能需要考虑以下事项:

  • 由于这是 PHP5 代码,请使用异常代替,trigger_error如有set_exception_handler必要,直到异常更普遍,但它绝对更干净,更面向未来。
  • 您正在使用单例,这不一定是一件坏事,但在这种情况下,例如,一个缺点是您只能处理一个到一个数据库的连接。
  • 我不知道您是否使用存储过程,但是存储过程也可能通过该方法返回结果集query()
  • 行尾有两个分号 ( ;;) new PDO

话虽如此,我认为您的查询方法并不太大,目前从那里的其他地方也没有太多可以回忆的东西。尽管一旦您看到可以从另一个函数调用的两三行代码,请将其拆分。这是DRY的好方法。

于 2009-03-06T04:33:25.073 回答
2

是和否。

对于简单的快速而肮脏的应用程序来说,这是一个很好的代码。

当您在更复杂的结构化应用程序中使用它时,就会出现问题。错误处理的位置取决于您正在执行的 sql。

此外,任何严重错误都将显示为“第 999 行的问题”类型错误,其中 999 在您的超级骗子例程中,您将难以将其追溯到特定的 sql 请求。

话虽如此,我一直在自己的小项目上做这种事情。

于 2009-03-06T04:11:01.680 回答
2

这是我使用的(只需用 $GLOBALS['db_conf'] 或其他东西替换对 Zzz_Config 的引用):

/**
 * Extended PDO with databse connection (instance) storage by name.
 */
class Zzz_Db extends PDO
{
    /**
     * Named connection instances.
     *
     * @var array
     */
    static private $_instances;

    /**
     * Retrieves (or instantiates) a connection by name.
     *
     * @param  string $name  Connection name (config item key).
     * @return Zzz_Db        Named connection.
     */
    static public function getInstance($name = null)
    {
        $name = $name === null ? 'db' : "db.$name";
        if (!isset(self::$_instances[$name])) {
            if (!$config = Zzz_Config::get($name)) {
                throw new RuntimeException("No such database config item: $name");
            }
            if (!isset($config['dsn'])) {
                if (!isset($config['database'])) {
                    throw new RuntimeException('Invalid db config');
                }
                $config['dsn'] = sprintf('%s:host=%s;dbname=%s',
                    isset($config['adapter']) ? $config['adapter'] : 'mysql',
                    isset($config['host']) ? $config['host'] : 'localhost',
                    $config['database']);
            }

            $db = self::$_instances[$name] = new self(
                $config['dsn'],
                isset($config['username']) ? $config['username'] : null,
                isset($config['password']) ? $config['password'] : null);
            $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
            //$db->setAttribute(PDO::ATTR_STATEMENT_CLASS, 'Zzz_Db_Statement');

            if ($db->getAttribute(PDO::ATTR_DRIVER_NAME) == 'mysql') {
                $db->setAttribute(PDO::ATTR_EMULATE_PREPARES, true);
                $db->exec('SET CHARACTER SET utf8');
            }
        }

        return self::$_instances[$name];
    }
}

用法应该是:

$db = Zzz_Db::getInstance(); // or Zzz_Db::getInstance('some_named_db')
$stmt = $db->prepare('SELECT ...

目标是将 db 配置保存在 *.ini 文件中(可由非编码人员编辑)。

于 2009-03-06T05:10:10.867 回答
1

prepare()我采取了另一种方式,并创建了一个类,该类使用/周围的一堆包装函数来扩展 PDO execute(),它比内置函数好得多(尽管这有点主观......)。

另一件事:除非您使用的是真正旧版本的 mysql (<=4.0) ,否则您应该设置PDO::ATTR_EMULATE_PREPARES为。false它默认为true,这是一个非常令人头疼的问题,并导致事情以模糊的方式中断......我猜这就是你首先拥有一个巨大的包装的原因bindParam()

于 2009-03-09T03:21:17.403 回答
0

要回答你的问题,如果它是一个好代码,问问你自己:
与直接使用 PDO 相比,我的代码的附加值是什么?

如果您找到一个好的答案,请使用您的代码。如果没有,我会坚持使用 PDO。

还可以尝试考虑实现Zend Framework的 DB 类,它可以独立工作并支持 PDO。

于 2009-03-06T18:16:33.847 回答