我正在尝试了解如何将PDO与“连接”类一起使用。
class db {
private static $dbh;
private function __construct(){}
private function __clone(){}
public static function connect() {
if(!self::$dbh){
self::$dbh = new PDO("mysql:host=localhost;dbname=database", "user", "password");
self::$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
}
return self::$dbh;
}
final public static function __callStatic( $chrMethod, $arrArguments ) {
$dbh = self::connect();
return call_user_func_array(array($dbh, $chrMethod), $arrArguments);
}
}
我从http://php.net/manual/en/book.pdo.php获取了上述内容,并略微修改了变量,但我想知道如何连接到此db类中的PDO连接对象?
$dbh = new db; //intiate connection???
$stmt = $dbh->prepare("SELECT * FROM questions WHERE id = :id"); // or should I do db::prepare.. ???
$stmt->bindParam(':id', $_GET['testid'], PDO::PARAM_INT);
if ($stmt->execute()) {
while ($row = $stmt->fetch()){
print_r($row);
}
}
有什么想法吗?感谢
答案 0 :(得分:5)
这或多或少是我做的。我不确定这是否是最佳方式,但它对我有用。
我的工厂类是我的代码的核心。从这里我生成我使用的所有课程。我的工厂类保存在单独的文件factory.class.php
中。
通过拥有工厂类,我只需要包含一次类文件。如果我没有这个,我必须为每个必须使用它的文件包含我的类文件。如果我稍后需要更新类文件名,我只需要在工厂类文件中进行更新。
创建工厂对象的另一个原因是减少数据库连接的数量。
我将每个类保存为单独的文件
工厂类
include_once('person.class.php');
include_once('tracking.class.php');
include_once('costAnalyzis.class.php');
include_once('activity.class.php');
class Factory {
function new_person_obj($id = NULL) { return new Person(Conn::get_conn(), $id); }
function new_tracking_obj($id = NULL) { return new Tracking(Conn::get_conn(), $id); }
function new_costAnalyzis_obj() { return new CostAnalyzis(Conn::get_conn()); }
function new_activity_obj() { return new Activity(Conn::get_conn()); }
}
连接类
// I have this class in the same file as Factory class
// This creates DB connection and returns any error messages
class Conn {
private static $conn = NULL;
private function __construct() {}
private static function init() {
$conf = self::config();
try {
self::$conn = new PDO($conf['dsn'], $conf['user'], $conf['pass'], array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8"));
}
catch (PDOException $e) {
// We remove the username if we get [1045] Access denied
if (preg_match("/\b1045\b/i", $e->getMessage()))
echo "SQLSTATE[28000] [1045] Access denied for user 'name removed' @ 'localhost' (using password: YES)";
else
echo $e->getMessage();
}
}
public static function get_conn() {
if (!self::$conn) { self::init(); }
return self::$conn;
}
// I used to get login info from config file. Now I use Wordpress constants
private static function config() {
$conf = array();
$conf['user'] = DB_USER; //$config['db_user'];
$conf['pass'] = DB_PASSWORD; //$config['db_password'];
$conf['dsn'] = 'mysql:dbname='.DB_NAME.';host='.DB_HOST;
return $conf;
}
}
不同的类对象
这些是你的课程。这是您处理数据的地方在我自己的代码中,我使用三层体系结构,将表示分离,从业务层和数据对象层分离。
class Person extends PersonDAO {
function getPersonData($id) {
$result = parent::getPersonData($id);
// Here you can work with your data. If you do not need to handle data, just return result
return $result;
}
}
// I only have SQL queries in this class and I only return RAW results.
class PersonDAO {
// This variable is also available from you mother class Person
private $db;
// Constructor. It is automatically fired when calling the function.
// It must have the same name as the class - unless you define
// the constructor in your mother class.
// The &$db variable is the connection passed from the Factory class.
function PersonDAO (&$db) {
$this->db = &$db;
}
public function get_data($id) {
$sql ="SELECT a, b, c
FROM my_table
WHERE id = :id";
$stmt = $this->db->prepare($sql);
$stmt->execute(array(':id'=> $id));
$result = $stmt->fetchAll(PDO::FETCH_ASSOC);
return $result;
}
public function get_some_other_data() {
$sql ="SELECT a, b, c
FROM my_table_b";
$result = $stmt->fetchAll(PDO::FETCH_ASSOC);
return $result;
}
}
为您的其他课程做同样的事情。
全部放在一起
请注意,我们只包含一个文件,即工厂文件。所有其他类文件都包含在Factory类文件中。
// Include factory file
include_once('factory.class.php');
//Create your factory object
$person = Factory::new_person_obj();
//Get person data
$data = $person->getPersonData('12');
// output data
print_r($data);
答案 1 :(得分:3)
据我了解,您希望拥有一个“连接类”,它实现PDO实例的延迟加载。然后,您希望代码中的对象可以从代码中的每个位置访问该连接,从而有效地创建单例。
不要这样做。
您正在清理应用程序中的全局状态,并且所有启用DB的类都与连接类的NAME紧密耦合。
我会推荐一些不同的方法。正如@Steven暗示的那样,您应该使用工厂来创建需要数据库连接的对象。
这是一个简化的实现。
class DataMapperFactory
{
protected $provider = null;
protected $connection = null;
public function __construct( Closure $provider )
{
$this->provider = $provider;
}
public function create( $name)
{
if ( $this->connection === null )
{
$this->connection = call_user_func( $this->provider );
}
return new $name( $this->connection );
}
}
你会喜欢这样:
$provider = function()
{
$instance = new PDO('mysql:......');
$instance->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$instance->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
return $instance;
};
$factory = new DataMapperFactory( $provider );
现在每次执行$factory->create('SomeClass')
时,它都会创建该类的新实例,并在构造函数中为其提供正确的数据库连接。并且,当第一次执行时,它将打开与DB的连接。