Php 组合与继承。我的数据库交互库应该使用什么?

Php 组合与继承。我的数据库交互库应该使用什么?,php,inheritance,dependency-injection,Php,Inheritance,Dependency Injection,考虑一个用PHP编写的数据库交互模块,其中包含用于与数据库交互的类。我还没有开始编写这个类,所以我无法给出代码片段 每个数据库表将有一个类,如下所述 User-用于与用户表交互的类。该类包含createUser、updateUser等函数 位置-用于与位置表交互的类。该类包含searchLocation、createLocation、updateLocation等函数 此外,我正在考虑创建另一个类,如下所示:- DatabaseHelper:一个类,它将有一个表示与数据库连接的成员。此类将包含用

考虑一个用PHP编写的数据库交互模块,其中包含用于与数据库交互的类。我还没有开始编写这个类,所以我无法给出代码片段

每个数据库表将有一个类,如下所述

User-用于与用户表交互的类。该类包含createUser、updateUser等函数

位置-用于与位置表交互的类。该类包含searchLocation、createLocation、updateLocation等函数

此外,我正在考虑创建另一个类,如下所示:-

DatabaseHelper:一个类,它将有一个表示与数据库连接的成员。此类将包含用于执行SQL查询的低级方法,如executeQuery(查询,参数)、executeUpdate(查询,参数)等

此时,我有两个选项可以在其他类中使用DatabaseHelper类:-

  • User和Locations类将扩展DatabaseHelper类,以便它们可以在DatabaseHelper中使用继承的executeQuery和executeUpdate方法。在这种情况下,DatabaseHelper将确保在任何给定时间只有一个到数据库的连接实例
  • DatabaseHelper类将通过创建User和Location实例的容器类注入User和Locations类。在这种情况下,容器将确保在任何给定时间应用程序中只有一个DatabaseHelper实例 我很快想到了这两种方法。我想知道采用哪种方法。可能这两种方法都不够好,在这种情况下,我想知道我可以使用的任何其他方法来实现数据库交互模块

    编辑:

    请注意,容器类将包含DatabaseHelper类型的静态成员。它将包含一个私有的静态getDatabaseHelper()函数,该函数将返回一个现有的DatabaseHelper实例,或者创建一个新的DatabaseHelper实例(如果不存在),在这种情况下,它将填充DatabaseHelper中的连接对象。容器还将包含名为makeUser和makeLocation的静态方法,它们将分别将DatabaseHelper注入用户和位置

    在阅读了一些答案后,我意识到最初的问题几乎已经得到了回答。但在我接受最终答案之前,仍有一个疑问需要澄清,答案如下


    当我要连接多个数据库而不是单个数据库时,该怎么办。DatabaseHelper类如何将其合并,容器如何在用户和位置对象中注入适当的数据库依赖项

    出于以下原因,我将使用依赖性注入:如果在某个时候您想为应用程序编写测试,它将允许您用存根类替换DatabaseHelper实例,实现相同的接口,但不真正访问数据库。这将使测试模型功能变得更加容易


    顺便说一句,为了让它真正有用,您的其他类(用户、位置)应该依赖于DatabaseHelper接口,而不是直接依赖于DatabaseHelper。(这是切换实现所必需的)

    让我们自上而下地回答您的问题,看看我能为您的发言添加什么

    每个数据库表将有一个类,如下所述

    用户-用于与用户表交互的类。该类包含createUser、updateUser等函数

    位置-用于与位置表交互的类。该类包含函数>,如searchLocation、createLocation、updateLocation等

    基本上你必须在这里做出选择。您描述的方法称为模式。对象本身知道如何以及在何处存储它。对于与数据库交互以创建/读取/更新/删除的简单对象,此模式非常有用

    如果数据库操作变得更广泛、更不容易理解,那么使用数据映射器(例如)通常是一个不错的选择。这是处理所有数据库交互的第二个对象,而对象本身(例如用户或位置)只处理特定于该对象的操作(例如登录或goToLocation)。如果您想利用存储对象的机会,只需创建一个新的数据映射器。您的对象甚至不知道实现中发生了什么变化。这将强制和强制执行

    还有其他选择,但这两种是实现数据库交互最常用的方法

    此外,我正在考虑创建另一个类,如下所示:-

    DatabaseHelper:一个类,它将有一个表示与数据库连接的静态成员。此类将包含用于执行SQL查询的低级方法,如executeQuery(查询,参数)、executeUpdate(查询,参数)等

    你在这里所描述的听起来像是一个故事。通常这不是一个好的设计选择。你真的确定不会有第二个数据库吗?可能不会,所以您不应该局限于只允许一个数据库连接的实现。与使用静态成员创建DatabaseHelper不同,您可以更好地使用一些方法创建数据库对象,这些方法允许您连接、断开连接、执行查询等。这样,如果您需要第二次连接,您就可以重用它

    此时,我有两个选项可以在其他类中使用DatabaseHelper类:-

  • User和Locations类将扩展DatabaseHelper类,以便它们可以使用继承的executeQuery和e
    class Controller {
        public function main() {
            $database = new Database('host', 'username', 'password');
            $database->selectDatabase('database');
            
            $user = new User($database);
            $user->name = 'Test';
            
            $user->insert();
            
            $otherUser = new User($database, 5);
            $otherUser->delete();
        }
    }
    
    class Database {
        protected $connection = null;
        
        public function __construct($host, $username, $password) {
            // Connect to database and set $this->connection
        }
        
        public function selectDatabase($database) {
            // Set the database on the current connection
        }
        
        public function execute($query) {
            // Execute the given query
        }
    }
    
    class User {
        protected $database = null;
        
        protected $id = 0;
        protected $name = '';
        
        // Add database on creation and get the user with the given id
        public function __construct($database, $id = 0) {
            $this->database = $database;
            
            if ($id != 0) {
                $this->load($id);
            }
        }
        
        // Get the user with the given ID
        public function load($id) {
            $sql = 'SELECT * FROM users WHERE id = ' . $this->database->escape($id);
            $result = $this->database->execute($sql);
            
            $this->id = $result['id'];
            $this->name = $result['name'];
        }
        
        // Insert this user into the database
        public function insert() {
            $sql = 'INSERT INTO users (name) VALUES ("' . $this->database->escape($this->name) . '")';
            $this->database->execute($sql);
        }
        
        // Update this user
        public function update() {
            $sql = 'UPDATE users SET name = "' . $this->database->escape($this->name) . '" WHERE id = ' . $this->database->escape($this->id);
            $this->database->execute($sql);
        }
        
        // Delete this user
        public function delete() {
            $sql = 'DELETE FROM users WHERE id = ' . $this->database->escape($this->id);
            $this->database->execute($sql);
        }
        
        // Other method of this user
        public function login() {}
        public function logout() {}
    }
    
    class Controller {
        public function main() {
            $database = new Database('host', 'username', 'password');
            $database->selectDatabase('database');
            
            $userMapper = new UserMapper($database);
            
            $user = $userMapper->get(0);
            $user->name = 'Test';
            $userMapper->insert($user);
            
            $otherUser = UserMapper(5);
            $userMapper->delete($otherUser);
        }
    }
    
    class Database {
        protected $connection = null;
        
        public function __construct($host, $username, $password) {
            // Connect to database and set $this->connection
        }
        
        public function selectDatabase($database) {
            // Set the database on the current connection
        }
        
        public function execute($query) {
            // Execute the given query
        }
    }
    
    class UserMapper {
        protected $database = null;
        
        // Add database on creation
        public function __construct($database) {
            $this->database = $database;
        }
        
        // Get the user with the given ID
        public function get($id) {
            $user = new User();
            
            if ($id != 0) {
                $sql = 'SELECT * FROM users WHERE id = ' . $this->database->escape($id);
                $result = $this->database->execute($sql);
                
                $user->id = $result['id'];
                $user->name = $result['name'];
            }
            
            return $user;
        }
        
        // Insert the given user
        public function insert($user) {
            $sql = 'INSERT INTO users (name) VALUES ("' . $this->database->escape($user->name) . '")';
            $this->database->execute($sql);
        }
        
        // Update the given user
        public function update($user) {
            $sql = 'UPDATE users SET name = "' . $this->database->escape($user->name) . '" WHERE id = ' . $this->database->escape($user->id);
            $this->database->execute($sql);
        }
        
        // Delete the given user
        public function delete($user) {
            $sql = 'DELETE FROM users WHERE id = ' . $this->database->escape($user->id);
            $this->database->execute($sql);
        }
    }
    
    class User {
        public $id = 0;
        public $name = '';
        
        // Other method of this user
        public function login() {}
        public function logout() {}
    }
    
    $controller = new Controller();
    
    class Controller {
        protected $databases = array();
        
        public function __construct() {
            $this->database['first_db'] = new Database('first_host', 'first_username', 'first_password');
            $this->database['first_db']->selectDatabase('first_database');
            
            $this->database['second_db'] = new Database('second_host', 'second_username', 'second_password');
            $this->database['second_db']->selectDatabase('second_database');
        }
        
        public function showUserAndLocation() {
            $user = new User($this->databases['first_database'], 3);
            $location = $user->getLocation($this->databases['second_database']);
            
            echo 'User ' . $user->name . ' is at location ' . $location->name;
        }
        
        public function showLocation() {
            $location = new Location($this->database['second_database'], 5);
            
            echo 'The location ' . $location->name . ' is ' . $location->description;
        }
    }
    
    public interface DatabaseHelperInterface {
      public executeQuery(....);
    }
    
    public class DatabaseHelperImpl implemnets DatabaseHelperInterface {
      public executeQuery(....) {
         //some code
      }
    
    public Class UserDaoInterface extends DatabaseHelperInterface {
       public createUser(....);
    }
    
    public Class UserDaoImpl extends DatabaseHelperImpl {
       public createUser(....) {
        executeQuery(create user query);
       }
    
    class DATABASE_CONFIG { // define various database connection details here (default/test/externalapi/etc) }
    
    // Data access layer
    class DataSource extends Object { // base for all places where data comes from (DB/CSV/SOAP/etc) }
    // - Database
    class DboSource extends DataSource { // base for all DB-specific datasources (find/count/query/etc) }
    class Mysql extends DboSource { // MySQL DB-specific datasource }
    // - Web service
    class SoapSource extends DataSource { // web services, etc don't extend DboSource }
    class AcmeApi extends SoapSource { // some non-standard SOAP API to wrestle with, etc }
    
    // Business logic layer
    class Model extends Object { // inject a datasource (definitions are in DATABASE_CONFIG) }
    // - Your models
    class User extends Model { // createUser, updateUser (can influence datasource injected above) }
    class Location extends Model { // searchLocation, createLocation, updateLocation (same as above) }
    
    // Flow control layer
    class Controller extends Object { // web browser controls: render view, redirect, error404, etc }
    // - Your controllers
    class UsersController extends Controller { // inject the User model here, implement CRUD, this is where your URLs map to (eg. /users/view/123) }
    class LocationsController extends Controller { // more CRUD, eg. $this->Location->search() }
    
    // Presentation layer
    class View extends Object { // load php template, insert data, wrap in design }
    // - Non-HTML output
    class XmlView extends View { // expose data as XML }
    class JsonView extends View { // expose data as JSON }