我正在尝试将 PDO 和 OOP 结合起来,但无法正常工作
Posted
技术标签:
【中文标题】我正在尝试将 PDO 和 OOP 结合起来,但无法正常工作【英文标题】:I'm trying to combine PDO and OOP, and can't get it to work 【发布时间】:2012-11-19 20:47:35 【问题描述】:所以我基本上有两个文件。最后我会得到更多,但我想创建一个名为DB
的类,它将使用 PDO 数据库操作,然后我将扩展这个类以使我的所有函数都用于处理数据库。所以DB
类,然后将扩展为dbADD
类,它将具有针对不同数据库表的所有添加功能。
这叫config.php
:
<?php
DEFINE ('DBHOST', 'localhost');
DEFINE ('DBUSER', 'REMOVED');
DEFINE ('DBPSW', 'REMOVED');
DEFINE ('DBNAME', 'REMOVED');
class DB
public $db;
private static $instance;
public function __constructor()
$config ['db'] = array(
'host' => DBHOST,
'username' => DBUSER,
'password' => DBPSW,
'dbname' => DBNAME,
);
$this->db = new PDO('mysql:host =' . $config['db']['host'] . ';dbname=' . $config['db']['dbname'],$config['db']['username'],$config['db']['password']) ;
public static function getInstance()
if (!isset(self::$instance))
$object = __CLASS__;
self::$instance = new $object;
return self::$instance;
public function GetArticles ($search)
$sql = "SELECT `FirstColumn`, `SrcColumn`, `article` FROM `test_table` WHERE `FirstColumn` = 23";
//$dbs = new DB();
$dbs = DB::getInstance();
$query = $dbs->db->prepare($sql);
//$query->bindValue(':search', $search, PDO::PARAM_INT);
$query->execute();
while ($row = $query->fetch(PDO::FETCH_OBJ))
// = $row['article'],'</br>';
$return = $row['article'];
return $return;
?>
这个文件是我的测试文件,它并不重要,只是一个测试场。致电test.php
:
<?php
require_once('app_core/config.php');
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Untitled Document</title>
<link rel="stylesheet" href="/style/style.css" type="text/css" media="screen" />
</head>
<body>
<?php
$db = new DB();
//echo $db->db;
//echo $db->GetTestDB();
//$test = $db->TestThis();
//print_r($test);
echo $db->GetArticles('23');
?>
</body>
</html>
如果可能的话,我还有另外两个担忧:第一个问题是安全问题——这是否是一种好习惯?另一个问题是如何隐藏带有此密码数据的文件,以便我可以使用它们但没有人可以读取它们?
【问题讨论】:
你认为的 OOP 不是 OOP。 OOP 不仅仅是把一些类放在一起。 【参考方案1】:建议:
如果可能,不要使用内联 SQL,因为如果您更改数据库的方案,假设您将列从 foo 重命名为 bar,您将必须找到所有使用 foo 的内联 SQL并将其更改为 bar。
你的想法很好,对不同的动作类型有一个通用的行为,但是没有实现它的意义,因为这个好想法之前已经实现了。例如,您可以尝试 Flourish,它是一种 ORM,可以为您提供很多帮助。
如果可以将密码存储在数据库中,请不要将密码存储在单独的文件中,但不要忘记加密密码并使用盐来改进加密。
【讨论】:
只想说第一点:我经常听到“改变数据库方案”的说法,但要成为魔鬼的拥护者,真的很难做到 ctrl+f 和 replace所有这些文字都有另一个名字?我只是看不到为那一件事使用 ORM 的理由。 这可能真的很难,因为它可以存在于不同的文件和不同的语言中。如果你的 foo 列被替换为 bar 并且你已经使用了 foo 列 10000 次,例如,'foo' 词出现在语义不同的字符串中并且在这些字符串中仍然有效,那么你的 Ctrl+F 方法是低效的。跨度> 也许吧,但为了争论,如果您提前计划 ORM,如果您需要替换foo
,您也可以计划使 ctrl+f 方法有效;)
ORM 和替换计划有很大的不同。 ORM 是动态的并自动支持数据库方案更改,而如果您使用替换计划,则必须特别注意代码中的所有表和列名称,以简化将来的名称更改。有时不使用 ORM 是合理的,但是当您使用具有许多用例的大型数据库开发大型系统时,没有 ORM 可能会变得非常困难。
ORM 是编码恶魔的小工具,可以引诱你产生额外的依赖。【参考方案2】:
好的,这里有很多事情要做,所以我将尝试一次解决一个问题,以使这个类以面向对象的方式正常运行(而不是一组不完全-相关方法)。
首先,你的构造函数:
// Make these private, will find out why in a moment...
private $db;
// __construct, not __constructor!!
private function __construct()
// This whole array doesn't serve any purpose because the constants
// are defined and available in all scopes
// while this array is local to the __construct().
// Just get rid of it and use the
// constants directly in the PDO connection
//$config ['db'] = array(
// 'host' => DBHOST,
// 'username' => DBUSER,
// 'password' => DBPSW,
// 'dbname' => DBNAME,
//);
// Use some error checking when establishing your connection
try
// Some extra bad whitespace removed around =
$this->db = new PDO('mysql:host=' . DBHOST . ';dbname=' . DBNAME, DBUSER, DBPSW);
catch (PDOException $e)
echo 'Connection failed: ' . $e->getMessage();
接下来是你的单例访问器 getInstance()。
// No code changes necessary....
public static function getInstance()
if (!isset(self::$instance))
$object = __CLASS__;
self::$instance = new $object;
return self::$instance;
由于您已经定义了一个以单例方式访问该类的方法,因此将 $db
属性和 __construct()
设为 private
。在任何时候你都不会调用$DB_class-instance = new DB()
来实例化它,或者调用$DB_class_instance->db
来直接访问连接。相反,您将调用DB::getInstance()
来访问单例实例,并调用GetArticles()
等方法来执行查询。
现在进入您的查询方法:
public function GetArticles ($search)
// Ok a SQL string, no problem...
$sql = "SELECT `FirstColumn`, `SrcColumn`, `article` FROM `test_table` WHERE `FirstColumn` = :search";
// There's no need for this. You already defined $db as
// a class property, so you should be using $this->db
// $dbs = DB::getInstance();
$query = $this->db->prepare($sql);
// bind the $search input parameter...
$query->bindParam(':search', $search);
// Test for success
if ($query->execute())
$row = $query->fetch(PDO::FETCH_OBJ)
// I suppose you know what you want here. If you're only expecting
// one article, there's no real need for the while loop.
// You can just fetch() once.
$return = $row->article;
// OR.....
// However, if you are expecting *multiple* rows, you should be accumulating them
// into an array like this:
$return = array();
while ($row = $query->fetch(PDO::FETCH_OBJ))
// Append to an array
$return[] = $row->article;
// OR to get multiple columns returned as an object...
$return[] = $row;
return $return;
else
// Query failed, return false or something
return FALSE;
最后是你的控制器代码:
// The constructor is private, so you can't do this
// $db = new DB();
// Instead you need to use getInstance()
$db = DB::getInstance();
// Returns an array, so print_r()
print_r($db->GetArticles('23'));
由于我们创建了类的$db
属性private
,因此无法在类外访问它。因此,您需要为您计划运行的任何其他查询定义类似于GetArticles()
的查询方法。如果您认为有时需要构建非类方法的即席查询,那么您可以将其更改为
public $db
然后,您可以在类之外执行以下操作,而不必构建类方法来执行此操作。但是,您确实仍然需要致电getInstance()
。
$dbs = DB::getInstance();
// Run a query via the PDO connection $dbs->db
$result = $dbs->db->query('SELECT * FROM sometable');
风格小问题:
这实际上不会导致问题,因为标识符不区分大小写,但在风格上它很奇怪。 define()
是函数调用,通常使用小写:
define('DBHOST', 'localhost');
define('DBUSER', 'REMOVED');
define('DBPSW', 'REMOVED');
define('DBNAME', 'REMOVED');
关于您的文件安全
只要您的网络服务器配置正确,其他人就无法读取这些文件。如果 Web 服务器将 .php 文件发送到 PHP 解释器而不是将其内容转储到浏览器,那么这些文件是安全的。如果您在共享主机上,并且该主机没有将您的文件与其他租户正确隔离,那就是他们的问题,唯一好的解决方案是获得更好的主机。
但是,将敏感文件存储在 Web 服务器的文档根目录之上是明智的。然后,即使是配置错误的 Web 服务器也不会意外地将其内容转储到客户端。 PHP 只能通过include
访问它们。
【讨论】:
我会删除它:D 对不起,我不知道,答案在哪里详细说明。 非常感谢,它成功了,我非常感谢。我是这个网站的新手,但我非常喜欢它。 @MrNewbProgrammer 乐于助人。为了将来参考,很多时候,一个范围如此之大的问题不会得到很好的回应,并且可能会因为过于广泛而立即被社区关闭。最好一次解决一个小问题,但这里的顺序安排得很好,我可以解决它们以将其构建成工作秩序。 大声笑——真的,否决者? 2 天后出现并在不发表评论的情况下投反对票? 什么?我不明白你的意思?【参考方案3】:由于 PDO 已经是一个对象,也许你根本不需要为它创建一个单例类。
相反,创建一个将 PDO 对象传递给的通用模型类。
<?php
class Model
private $pdo;
__construct(PDO $pdo)
$this->pdo = $pdo
// generic model methods go here
然后您可以对它进行子类化并充实您创建的每个模型的功能。
用法类似于:
$PDO = new PDO("mysql:host=DBHOST;dbname=DBNAME", DBUSER, DBPSW);
$myModel = new MyModel($pdo);
$bob = $myModel->getByName('bob');
$articles = new Articles($pdo);
$recentArticles = $articles->getRecent(new Date());
关于安全性,本文提供了一些不错的通用提示,http://www.tuxradar.com/practicalphp/17/0/0。事实上,整个指南都非常有帮助。
【讨论】:
以上是关于我正在尝试将 PDO 和 OOP 结合起来,但无法正常工作的主要内容,如果未能解决你的问题,请参考以下文章