如何正确设置PDO连接
有时我会看到有关连接到数据库的问题。
大多数答案不是我做的方式,或者我可能只是不正确地得到答案。 无论如何; 我从来没有想过,因为我这样做的方式适用于我。
但是这是一个疯狂的想法。 也许我这样做是完全错误的,如果是这样的话; 我真的想知道如何正确连接到使用PHP和PDO的MySQL数据库,并使其易于访问。
以下是我如何做到这一点:
首先,我的文件结构(剥离) :
public_html/ * index.php * initialize/ -- load.initialize.php -- configure.php -- sessions.php
的index.php
在最顶层,我require('initialize/load.initialize.php');
。
load.initialize.php
# site configurations require('configure.php'); # connect to database require('root/somewhere/connect.php'); // this file is placed outside of public_html for better security. # include classes foreach (glob('assets/classes/*.class.php') as $class_filename){ include($class_filename); } # include functions foreach (glob('assets/functions/*.func.php') as $func_filename){ include($func_filename); } # handle sessions require('sessions.php');
我知道有一个更好或更正确的方法来包含类,但不记得它是什么。 还没有时间来看看它,但我认为这是autoload
东西。 像那样的东西…
的configure.php
在这里,我基本上只是重写一些php.ini-属性,并为网站做一些其他的全局configuration
connect.php
我把连接放到一个类中,所以其他类可以扩展这个…
class connect_pdo { protected $dbh; public function __construct() { try { $db_host = ' '; // hostname $db_name = ' '; // databasename $db_user = ' '; // username $user_pw = ' '; // password $con = new PDO('mysql:host='.$db_host.'; dbname='.$db_name, $db_user, $user_pw); $con->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION ); $con->exec("SET CHARACTER SET utf8"); // return all sql requests as UTF-8 } catch (PDOException $err) { echo "harmless error message if the connection fails"; $err->getMessage() . "<br/>"; file_put_contents('PDOErrors.txt',$err, FILE_APPEND); // write some details to an error-log outside public_html die(); // terminate connection } } public function dbh() { return $this->dbh; } } # put database handler into a var for easier access $con = new connect_pdo(); $con = $con->dbh(); //
在这里,我相信自从我最近开始学习OOP,并使用PDO而不是使用mysql之后,还有很大的改进余地。
所以我刚刚跟着几个初学者教程,尝试了不同的东西…
sessions.php
除了处理常规会话之外,我还将一些类初始化为这样的会话:
if (!isset($_SESSION['sqlQuery'])){ session_start(); $_SESSION['sqlQuery'] = new sqlQuery(); }
这样这个class就可以到处都是。 这可能不是好的做法(?)…
无论如何,这是这种方法可以让我从任何地方做到这一点:
echo $_SESSION['sqlQuery']->getAreaName('county',9); // outputs: Aust-Agder (the county name with that id in the database)
在我的sqlQuery
– 类中 , extends
我的connect_pdo
– 类 ,我有一个名为getAreaName
的公共函数处理对我的数据库的请求。
我觉得很整齐。
奇迹般有效
所以这基本上是我如何做的。
另外,无论何时我需要从不在一个类中的数据库中获取某些东西,我只需要做类似如下的事情:
$id = 123; $sql = 'SELECT whatever FROM MyTable WHERE id = :id'; $qry = $con->prepare($sql); $qry -> bindParam(':id', $id, PDO::PARAM_INT); $qry -> execute(); $get = $qry->fetch(PDO::FETCH_ASSOC);
因为我把连接放到connect_pdo.php里面的一个variables中,所以我只是提到它,我很好。 有用。 我得到了我的预期的结果…
但不pipe那个 如果你们能告诉我我是否在这里,我会很感激。 我应该做的,我可以或应该改善的地方,以改善等…
我渴望学习…
目标
正如我所看到的,你在这种情况下的目标是双重的:
- 创build并维护每个数据库的单个/可重用连接
- 确保连接已正确设置
解
我会build议使用匿名函数和工厂模式来处理PDO连接。 它的使用看起来像这样:
$provider = function() { $instance = new PDO('mysql:......;charset=utf8', 'username', 'password'); $instance->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); $instance->setAttribute(PDO::ATTR_EMULATE_PREPARES, false); return $instance; }; $factory = new StructureFactory( $provider );
然后在不同的文件或更低的相同的文件中:
$something = $factory->create('Something'); $foobar = $factory->create('Foobar');
工厂本身应该是这样的:
class StructureFactory { protected $provider = null; protected $connection = null; public function __construct( callable $provider ) { $this->provider = $provider; } public function create( $name) { if ( $this->connection === null ) { $this->connection = call_user_func( $this->provider ); } return new $name( $this->connection ); } }
这样可以让你有一个集中的结构,确保只在需要的时候才build立连接。 这也会使unit testing和维护的过程变得更容易。
在这种情况下的提供者将在引导阶段被find。 这种方法也会给出一个明确的位置来定义configuration,用于连接到数据库。
请记住,这是一个非常简单的例子 。 您还可以通过观看以下两个video获益:
- 全局状态和单身
- 不要找东西!
另外,我强烈推荐阅读关于使用PDO 的正确教程 (在线有错误的教程日志)。
我build议不要使用$_SESSION
全局访问你的数据库连接。
你可以做一些事情(按照从最差到最佳的方式):
- 在函数和类中使用
global $dbh
访问$dbh
-
使用一个单一的registry,并访问全局,如下所示:
$registry = MyRegistry::getInstance(); $dbh = $registry->getDbh();
-
将数据库处理程序注入到需要它的类中,如下所示:
class MyClass { public function __construct($dbh) { /* ... */ } }
我会强烈推荐最后一个。 它被称为dependency injection(DI),控制反转(IoC),或简单的好莱坞原则(不要打电话给我们,我们会打电话给你)。
但是,它稍微先进一些,需要更多的“布线”而没有框架。 所以,如果dependency injection对你来说太复杂了,那么使用一个单例registry而不是一堆全局variables。
最近我自己也来了一个类似的回答/问题。 这就是我所做的,如果有人感兴趣:
<?php namespace Library; // Wrapper for \PDO. It only creates the rather expensive instance when needed. // Use it exactly as you'd use the normal PDO object, except for the creation. // In that case simply do "new \Library\PDO($args);" with the normal args class PDO { // The actual instance of PDO private $db; public function __construct() { $this->args = func_get_args(); } public function __call($method, $args) { if (empty($this->db)) { $Ref = new \ReflectionClass('\PDO'); $this->db = $Ref->newInstanceArgs($this->args); } return call_user_func_array(array($this->db, $method), $args); } }
要调用它,你只需要修改这一行:
$DB = new \Library\PDO(/* normal arguments */);
而types暗示,如果你正在使用它(\ Library \ PDO $ DB)。
这与被接受的答案和你的答案非常相似。 然而它有一个显着的优势。 考虑这个代码:
$DB = new \Library\PDO( /* args */ ); $STH = $DB->prepare("SELECT * FROM users WHERE user = ?"); $STH->execute(array(25)); $User = $STH->fetch();
虽然它可能看起来像正常的PDO(它只是由\Library\
而改变),但实际上它不会初始化对象,直到您调用第一个方法(无论哪一个)为止。 这使得它更加优化,因为PDO对象创build稍微昂贵。 这是一个透明的类,或者叫做Ghost ,一种延迟加载的forms。 您可以将$ DB视为普通的PDO实例,传递给它,执行相同的操作等。
$dsn = 'mysql:host=your_host_name;dbname=your_db_name_here'; // define host name and database name $username = 'you'; // define the username $pwd='your_password'; // password try { $db = new PDO($dsn, $username, $pwd); } catch (PDOException $e) { $error_message = $e->getMessage(); echo "this is displayed because an error was found"; exit(); }