我有一个简单的应用程序,说它有一些类和一个处理数据库请求的"额外".目前我每次使用应用程序时都会创建数据库对象,但在某些情况下,不需要数据库连接.我这样做(PHP顺便说一句):
$db = new Database();
$foo = new Foo($db); // passing the db
Run Code Online (Sandbox Code Playgroud)
但有时该$foo对象不需要db访问,因为只调用没有数据库操作的方法.所以我的问题是:处理这种情况的专业方法是什么/如何仅在需要时创建数据库连接/对象?
我的目标是避免不必要的数据库连接.
有人最近问了一个关于Ghost设计模式的问题 - 我以前没见过.
什么是Ghost设计模式以及如何实现?我只能在网上找到它的片段.
我在另一个问题上看到了这个代码 - 第二个答案链接,第一个评论是它是一个静态工厂反模式,它违反了SRP:
class User {
public static function create($userid) {
// get user from the database
// set $isPartner to true or false
// set $isClient to true or false
// set $isModerator to true or false
if ($isPartner) {
return new Partner($userid);
} elseif ($isClient) {
return new Client($userid);
} elseif ($isModerator) {
return new Moderator($userid);
} else {
return new User($userid);
}
}
}
$person = User::create($userid);
Run Code Online (Sandbox Code Playgroud)
现在我可以理解为什么它违反了SRP - 因为它处理连接到数据库以及构建新类,但除此之外我不确定我是否理解为什么它是反模式.
我想编写一些与此类似的代码,所以我现在想知道是否要避免它,这是我的代码(伪代码):
class DatabaseClass()
{
...deals …Run Code Online (Sandbox Code Playgroud) 这是我的问题,我有一个很小的PHP MVC框架我建立.现在,当我在控制器中,我应该能够加载一个模型.我的模型名称像Users.php,Pages.php等数据库表.
所有控制器都扩展了BaseController,并且所有模型都扩展了BaseModel,这样我可以为所有控制器提供一些方法.像任何控制器一样,我可以像这样使用loadModel方法:
$usersModel = $this->loadModel("Users");
Run Code Online (Sandbox Code Playgroud)
现在$ usersModel将是表示用户数据库表的对象,从那里我应该打开数据库连接,并从users表中获取,更新,删除东西.
要从我的模型获取数据库连接,baseModel有方法loadDatabase(),我使用它像这样:
$database = $this->loadDatabase();
Run Code Online (Sandbox Code Playgroud)
这将返回PDO周围的薄层,所以从那里我可以使用这样的东西:
$data = $database->fetchAssoc("SELECT * FROM users WHERE name = ?", array("someone"));
Run Code Online (Sandbox Code Playgroud)
这就是我将一些$ data从Model返回给Controller的方法.
所以基本上,Controller可以加载模型,然后在该模型上调用返回某些数据或更新或删除等的方法.
现在,Controller可以加载多个模型.每个模型都应该加载数据库,这就是它变得复杂的地方.我只需要一个数据库连接.
这是loadDatabase方法的外观:
public function loadDatabase()
{
// Get database configuration
require_once("Application/Config/Database.php");
// Build configuration the way Database Object expects it
$dns = "{$db_config['db_driver']}:host={$db_config['db_host']};dbname={$db_config['db_name']}";
$username = $db_config['db_user'];
$password = $db_config['db_pass'];
$options = $db_config['db_options'];
// Return new Database object
return new \Core\Database\Database($dns, $username, $password, $options);
}
Run Code Online (Sandbox Code Playgroud)
因此,在加载Database对象之前,我必须加载数据库连接的配置,因为Database对象__constructor需要它.然后我实例化新的数据库对象并返回它.
现在我卡住了,我不知道这是从模型加载数据库的正确方法吗?我应该如何设置它,如何从模型内部加载数据库,因此始终只有一个数据库对象实例.如果我从Controller那样做这样的事情,那就更好了:
$users = $this->loadModel("Users");
$pages = $this->loadModel("Pages");
$users->doSomethingThatNeedsDatabase(); …Run Code Online (Sandbox Code Playgroud) 在询问有关PDO查询的另一个问题时,我被告知将我的PDO连接对象保存为全局,以便在我调用数据库查询的各种函数中使用它通常是不好的做法.
以下是我通常使用PDO对象的方法:
function somefunction(){
global $pdo;
$statement = $pdo->prepare("some query");
$statement->execute();
}
Run Code Online (Sandbox Code Playgroud)
我读过的论点更多的是代码维护和调试,很难跟踪谁修改了PDO对象以及它在代码中的位置.其他人只是拒绝使用全局变量来存储PDO对象,但无法真正解释为什么全局变量是一种糟糕的方法.
但是,对于只有一个数据库的中小型项目,使用全局变量真的有缺点吗?我通常单独使用连接脚本和函数脚本,其中函数脚本require_once()连接脚本,我的PDO对象创建在那里.通过这种方式,我的连接始终建立,并且对PDO对象的所有修改都在我的连接脚本中完成.
使用这种方法有任何根本缺陷吗?
我正在尝试基于OOP设计我的网站,但我遇到了如何设计数据库连接的麻烦.目前,我正在抽象类Connector中创建一个私有静态PDO对象.显然,任何需要与数据库交互的东西都会扩展这个类.我一直在翻转如何确保脚本中只有一个连接或PDO对象,因为某些页面需要多个扩展Connector的类.许多人似乎为此目的推荐了Singleton模式,但我目前这样做的方式似乎也完成了同样的事情.
这是我目前的代码.
abstract class Connector
{
private static $dbh;
public function __construct()
{
try
{
self::$dbh = new PDO(...);
self::$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
}
catch(PDOException $e)
{
die($e->getMessage());
}
}
public function getDB()
{
return self::$dbh;
}
}
Run Code Online (Sandbox Code Playgroud)
然后任何子类都会像这样使用它.
class Subclass extends Connector
{
public function interactWithDB()
{
$stmt = $this->getDB()->prepare(...);
// etc...
}
}
Run Code Online (Sandbox Code Playgroud)
从理论上讲,我认为子类的每个实例都应该始终访问同一个PDO实例.这段代码是否真的有意义,或者我是否以某种方式误解了静态属性?这是不好的设计/实践,还是Singleton有更多的优势?
如果有什么不清楚的话请评论,谢谢!
编辑:
Connector类并不仅仅是为了保存PDO对象而存在.它的析构函数关闭连接(使其为null)并且它包含isValueTaken等函数,它检查数据库中是否已有值.它具有以下抽象功能
abstract function retrieveData();
abstract function setData();
Run Code Online (Sandbox Code Playgroud)
例如,我有一个扩展Connector的User类.它定义了setData()来在数据库中注册用户.我不知道这是否会对回应产生影响.
以下代码是否显示了缓存完全构建的页面和数据库查询的可接受方式?
构建页面的缓存是__construct在控制器中启动的,然后完成__destruct,在此示例中,所有页面都缓存为文件的默认值15分钟.
查询缓存完成,apc并且它们在每个查询的指定时间内存储在内存中.在实际站点中,将有另一个apc缓存类,以便在需要时可以更改它.
我的目标是建立最简单的mvc,我失败了还是我在正确的轨道上?
调节器
//config
//autoloader
//initialiser -
class controller {
var $cacheUrl;
function __construct(){
$cacheBuiltPage = new cache();
$this->cacheUrl = $cacheBuiltPage->startFullCache();
}
function __destruct(){
$cacheBuiltPage = new cache();
$cacheBuiltPage->endFullCache($this->cacheUrl);
}
}
class forumcontroller extends controller{
function buildForumThread(){
$threadOb = new thread();
$threadTitle = $threadOb->getTitle($data['id']);
require 'thread.php';
}
}
Run Code Online (Sandbox Code Playgroud)
模型
class thread extends model{
public function getTitle($threadId){
$core = Connect::getInstance();
$data = $core->dbh->selectQuery("SELECT title FROM table WHERE id = 1");
return $data;
} …Run Code Online (Sandbox Code Playgroud) 为了掌握MVC,我写了以下内容:
//Model/Model.php
class Model
{
private $dbh;
public function __construct()
{
$this->dbh = dbConnect();
}
private function dbConnect()
{
//return database connection
}
public function crudMethod()
{
//interact with databse using $this->dbh
}
}
//Controller/Controller.php
class Controller
{
public $modelConnection;
public function __construct()
{
$this->modelConnection = new Model();
}
}
//View/index.php
$obj = new Controller;
$obj->modelConnection->crudMethod();
?>
Run Code Online (Sandbox Code Playgroud)
看看我的代码,我觉得我完全忽略了这一点.
控制器不提供实际值,我也可以直接实例化Model类.
模型类是否应该被实例化?控制器内部还是外部?或者这完全是不好的做法?我如何改进这种结构以支持MVC范例?
PHP和OOP的新手所以请耐心等待......在设计和编写我的第一个PHP和OOP网站之后,我已经处于乐观的早期阶段,经过一生的写作糟糕的M $ VBA垃圾.
我有一个类"User",它有一个带有相关数据库调用的save方法等...(实际上我有DB和DBUtils类来处理连接和CRUD - 我的业务类只调用DB Utils上的select,update,delete方法并传递数据的关联数组)
Anywho ...我的"用户"类由"Admin"类扩展,除了"User"yada yada之外还有一些额外的属性......
在"管理员"中处理保存方法的最佳方法是什么?我知道如果我向Admin类添加一个save方法,它将取代User上的那个,但我不希望它.我想在Admin上编写save方法,只处理特定于Admin对象的属性等,以及继承自"User"的属性,以便在User save方法中处理.
那有意义吗?它是我正在寻找的特定OOP模式吗?任何有关如何设计和构造此代码的帮助或指导将不胜感激.
编辑:哇!感谢下面的所有答案.不确定哪个是我的首选.我将不得不做一些游戏......
我有一些PHP代码连接到购物车API(SOAP)端点.这不是针对一个中央服务器,而是针对任意数量的用户的特定端点URL.
现在我有几个不同的类,它们都创建自己与用户API的连接.
例如,
CartProduct.php - > updateProduct()(创建api连接)
CartCategory.php - > updateCategory()(创建api连接)
我正在考虑使用Singleton来共享远程连接,但在阅读了有关SO和一些博客的问题之后,显然每个人都讨厌Singleton.
就我而言,我认为连接池没有意义.我正在连接到远程用户的网站,所以我不只是想打开5个连接并且可能会减慢他们的网站速度.我想在这种情况下我真的想在这个应用程序调用之间共享一个连接.我认为在数据库的情况下,连接池是有意义的,但不适用于远程用户API.从理论上讲,我想我们应该考虑如果用户同时尝试运行updateProduct和updateCategory会发生什么......会破坏系统吗?
是否有一个设计模式在这里有意义打开一个连接,几个不同的类可以共享?
我为简单的MVC模式建立了新的数据库连接类。
我需要知道这是正确的方法。
<?php
include_once 'config.php';
class dbModel{
private $dbSys = "";
private $dbHost = "";
private $dbUser = "";
private $dbPass = "";
private $dbName = "";
private con = false;
public function __construct(){
$this->dbSys = DB_SYS;
$this->dbHost = DB_HOST;
$this->dbUser = DB_USER;
$this->dbPass = DB_PASS;
$this->dbName = DB_NAME;
if (!$this->con){
try{
$this->con = new PDO($this->dbSys.':host='.$this->dbHost.';dbname='.$this->dbName, $this->dbUser, $this->dbPass);
return $this->con;
} catch (PDOException $e){
echo $e->getMessage();
exit();
}
}else{
return $this->con;
}
}
}
?>
Run Code Online (Sandbox Code Playgroud)
我将用于数据库配置的config.php文件作为一个单独的文件包含在内。我正在从我项目的其他模型中的该数据库连接类创建新对象,并编写sql并运行查询。
我测试了这段代码,这可以正常工作。但是我需要知道正确的方法。
请让我知道这是正确的方法。