代码之家  ›  专栏  ›  技术社区  ›  Marshmellow1328

从PHP应用程序中提取数据库的最佳方法是什么?

  •  6
  • Marshmellow1328  · 技术社区  · 15 年前

    我的问题是,如何从应用程序的模型层抽象数据库连接?主要关注的是能够轻松地从不同类型的数据库中进行更改。也许您可以从一个平面文件开始,用逗号分隔的数据库。然后要移动到SQL数据库。然后,您决定LDAP实现会更好。一个人怎么能轻易地计划这样的事情呢?

    举个简单的例子,假设您有一个用户名、姓氏和电子邮件用户。表示它的非常简单的PHP类可能如下所示(请忽略公共实例变量的问题):

    <?php
    
    class User {
      public $first;
      public $last;
      public $email;
    }
    
    ?>
    

    我经常看到人们使用的DAO类中嵌入了SQL,例如:

    <?php
    
    class UserDAO {
      public $id;
      public $fist;
      public $last;
      public $email;
    
      public function create( &$db ) {
        $sql = "INSERT INTO user VALUES( '$first', '$last', '$email' )";
        $db->query( $sql );
      }
    }
    
    ?>
    

    我对这种策略的问题是,当您想要更改数据库时,您必须更改每个DAO类的创建、更新、加载、删除函数来处理您的新类型的数据库。即使你有一个程序可以为你自动生成它们(我并不特别喜欢这个程序),你也必须编辑这个程序使它现在工作。

    你对如何处理这个有什么建议?

    我目前的想法是用自己的创建、删除、更新、加载函数为DAO对象创建一个超级类。但是,这些函数将获取DAO的属性数组并生成查询本身。这样,唯一的SQL就在superdao类中,而不是分散在几个类中。然后,如果您想更改数据库层,您只需更改SuperDAO类生成查询的方式。优势?缺点?可预见的问题?好,坏,丑?

    10 回复  |  直到 8 年前
        1
  •  7
  •   Ben S    15 年前

    使用一个 ORM 通常是提取数据库的首选方法。上提供了一个不完整的PHP实现列表 Wikipedia .

        2
  •  8
  •   Alister Bulman    15 年前

    您可以使用各种框架,如pdo、pear::mdb2或zend_db,但老实说,在12年的PHP开发过程中,我从未需要从一种类型的数据存储基础结构过渡到另一种类型。

    从类似于sqlite的东西到mysql,这是非常罕见的。如果你做的不止这些,你还是会遇到更大的问题。

        3
  •  3
  •   romaninsh    8 年前

    我提出了一个有趣的概念,允许开发人员创建 数据库不可知论 代码,但与ORM不同 不牺牲表现 :

    • 使用简单(如ORM)
    • 数据库不可知:用于SQL、NoSQL、文件等
    • 如果供应商允许,始终优化查询(子选择、映射减少)

    结果是 Agile Data - database access framework (详细说明见视频)。

    用数据库不可知代码和敏捷数据解决现实任务

    1. 从开始 describing business models .
    2. 创建持久性驱动程序 $db (用于数据库连接的花哨词),可以是csv文件、sql或ldap。
    3. 将模型与 美元分贝 表达你的 Action
    4. 执行 行动

    此时,框架将根据数据库的功能确定最佳策略,映射字段声明,为您准备和执行查询,这样您就不必编写它们了。

    代码示例

    我的下一个代码片段解决了确定 我们所有的VIP客户目前的债务总额是多少 . Schema:

    enter image description here

    接下来是独立于供应商的代码:

    $clients = new Model_Client($db);
    // Object representing all clients - DataSet
    
    $clients -> addCondition('is_vip', true);
    // Now DataSet is limited to VIP clients only
    
    $vip_client_orders = $clients->refSet('Order');
    // This DataSet will contain only orders placed by VIP clients
    
    $vip_client_orders->addExpression('item_price')->set(function($model, $query){
        return $model->ref('item_id')->fieldQuery('price');
    });
    // Defines a new field for a model expressed through relation with Item
    
    $vip_client_orders->addExpression('paid')
      ->set(function($model, $query){
        return $model->ref('Payment')->sum('amount');
    });
    // Defines another field as sum of related payments
    
    $vip_client_orders->addExpression('due')->set(function($model, $query){
        return $query->expr('{item_price} * {qty} - {paid}');
    });
    // Defines third field for calculating due
    
    $total_due_payment = $vip_client_orders->sum('due')->getOne();
    // Defines and executes "sum" action on our expression across specified data-set
    

    结果查询if 美元分贝 是SQL:

    select sum(
      (select `price` from `item` where `item`.`id` = `order`.`item_id` )
      * `order`.`qty`
      - (select sum(`payment`.`amount`) `amount` 
         from `payment` where `payment`.`order_id` = `order`.`id` )
    ) `due` from `order` 
    where `order`.`user_id` in (
      select `id` from `user` where `user`.`is_client` = 1 and `user`.`is_vip` = 1 
    )
    

    对于其他数据源,执行策略可能会带来更多的数据,但会始终如一地工作。

    我认为我的方法是抽象数据库的一个很好的方法,我正在努力在麻省理工学院的许可下实现它:

    https://github.com/atk4/data

        4
  •  2
  •   Ólafur Waage    15 年前

    你应该调查一下 PDO library.

    PDO提供了一个数据访问抽象层,这意味着,无论您使用的是哪个数据库,您都可以使用相同的函数来发出查询和获取数据。

    PDO不提供数据库抽象;它不重写SQL或模拟缺少的功能。如果需要这个工具,您应该使用一个完整的抽象层。

        5
  •  2
  •   Community CDub    7 年前

    最好的方法是使用ORM(对象关系映射)库。其中有很多是针对PHP的。我个人用过,可以推荐 doctrine orm (我将它与Silex结合使用,后者是一个极简的PHP框架)。

    下面是一个关于php表单的stackoverflow线程,如果您愿意,可以在其中找到一些替代方法: Good PHP ORM Library?

        6
  •  1
  •   Greg    15 年前

    理论上听起来不错,但很像 YAGNI .

    最好使用SQL库,例如 PDO 在到达之前不要担心LDAP。

        7
  •  1
  •   EvanK    15 年前

    一般来说,如果你在使用数据库时遇到麻烦,那么你的应用程序将受益于使用特定于数据库“品牌”的功能,并且将是一个更可靠的应用程序。

    从一个数据库系统转移到另一个数据库系统是非常罕见的。唯一一次您可能会现实地认为值得实现的AA特性是,如果您正在编写某种松散耦合的系统或框架,以供大规模消费(如Zend框架或Django)。

        8
  •  1
  •   Collin Klopfenstein    15 年前

    我一直喜欢使用ADODB。从我所看到的来看,它看起来能够在非常不同的平台之间切换。

    http://adodb.sf.net

        9
  •  1
  •   BIOHAZARD    11 年前

    事实上,“在哪里实现数据访问逻辑”主题的解决方案不复杂。您需要记住的是,您的模型代码必须与数据访问代码分开。

    像:

    使用某些业务逻辑user::name()方法对层进行建模

    class User 
    {
      public $first;
      public $last;
      public $email;
      public function name ()
      {
          return $this->first." ".$this->last;
      }
    }
    

    数据访问层:

    class Link
    {
        $this->connection;
        public function __construct ()
        {
            $this->connection = PDO_Some_Connect_Function();
        }
        public function query ($query)
        {
            PDO_Some_Query ($this->connection, $query);
        }
    
    }
    
    class Database
    {
        public $link;
        public function __construct ()
        {
            $this->link = new Link();
        }
        public function query ($query)
        {
            $this->link->query ($query);
        }
    }
    
    class Users
    {
        public $database;
        public function __construct (&$database)
        {
             $this->database = &$database;
        } 
        public save ($user)
        {
            $this->database->link->query ("INSERT INTO user VALUES( '$user->first', '$user->last', '$user->email' ))";
        }
    

    用途:

    $database = new Database();
    
    $users = new Users();
    
    $users->save (new User());
    

    在本例中,很明显您可以随时更改数据访问类链接,该链接将对任何内容运行查询(这意味着您可以在更改链接时在任何服务器上保存用户)。

    同时,您有一个干净的模型层代码,它独立生活,不知道是谁和在哪里保存它的对象。

    此外,这里的数据库类似乎是不必要的,但实际上它可以产生一些伟大的想法,比如在一个项目中为多个DB连接收集一个实例的多个链接。

    此外,还有一个简单、功能强大的单一文件框架,叫做 db.php ( http://dbphp.net )它是基于我在这里描述的模式构建的,甚至可以自动创建表,从而能够完全控制其标准的SQL字段/表设置,并在每次需要时将数据库结构与模型同步。

        10
  •  0
  •   bcosca    14 年前

    Axon ORM 自动检测架构中的更改,而无需重新生成代码。