如何正确设置PDO连接


92

我不时看到有关连接数据库的问题。
大多数答案不是我的方法,否则我可能只是无法正确获得答案。无论如何; 我从未考虑过,因为我的工作方式对我有效。

但是这里有个疯狂的想法;也许我做错了所有,如果是这样的话;我真的很想知道如何使用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 -properties并对该站点进行其他一些全局配置

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();
}

这样,该课程可在所有地方使用。这可能不是一个好习惯(?)...
无论如何,这就是我可以从任何地方做的事情:

echo $_SESSION['sqlQuery']->getAreaName('county',9);  // outputs: Aust-Agder (the county name with that id in the database)

在my sqlQuery- class(即extendsmy connect_pdo- class)内部,有一个名为的公共函数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内的变量中,因此我只用引用它就可以了。有用。我得到了预期的结果...

但是不管怎样;如果你们能告诉我我是否要离开这里,我将不胜感激。我应该做的是,我应该或应该改变以改进的领域等。

我渴望学习...


9
您应该使用自动加载器,而不是一次在应用程序中包含每个文件
Lusitanian

4
这个问题可能是最好的代码审查
斑的幽灵

Answers:


105

目标

正如我所看到的,在这种情况下,您的目标是双重的:

  • 为每个数据库创建并维护一个/可重复使用的连接
  • 确保已正确建立连接

我建议同时使用匿名函数和工厂模式来处理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 );
    }

}

这种方式将使您拥有集中式的结构,从而确保仅在需要时才创建连接。这也将使单元测试和维护过程变得更加容易。

在这种情况下,提供程序将在引导阶段找到。这种方法还将提供一个清晰的位置,用于定义配置,以用于连接到数据库。

请记住,这是一个极其简化的示例。您还可以从以下两个视频中受益:

另外,我强烈建议您阅读有关PDO使用的正确教程(在线上有糟糕的教程的日志)。


3
因为甚至PHP5.3都将接近停产期。实际上,大多数具有过时PHP版本的网站实际上只是Wordpress的廉价托管。在我看来,5.3之前的环境对专业发展的影响(它们可以从类似的摘要中受益)可以忽略不计。
tereško

5
@thelolcat我同意你的看法。这或多或少相同的答案。也就是说,如果您没有看到完全不同的事实。
PeeHaa

1
@thelolcat,那么您应该了解什么是依赖注入。而不是继续让自己尴尬。有趣的是,上面帖子中的第二个视频(标题为“ Do n't Look For Things”)实际上解释了DI是什么以及如何使用它……但是,您当然对于这些琐碎的事情太过高级了。
tereško

2
这是一个旧的答案,但是是一个很好的答案-并最终链接到Mysql pdo
草莓

1
@teecee,您应该首先学习如何使用PDO。我会推荐本教程:wiki.hashphp.org/PDO_Tutorial_for_MySQL_Developers,因为它是专为希望从其迁移mysql_*到PDO的人而设计的。然后,您可以返回查看此解决方案,该解决方案针对已使用PDO但需要一种在多个类之间共享DB连接的方法的解决方案。
tereško

24

我建议不要使用$_SESSION全局访问您的数据库连接。

您可以做以下几件事之一(从最坏到最好的顺序实践的):

  • $dbh使用访问global $dbh在函数和类内部
  • 使用单例注册表,并进行全局访问,如下所示:

    $registry = MyRegistry::getInstance();
    $dbh = $registry->getDbh();
  • 将数据库处理程序注入需要它的类中,如下所示:

    class MyClass {
        public function __construct($dbh) { /* ... */ }
    }

我强烈推荐最后一个。这被称为依赖注入(DI),控制反转(IoC)或简称为好莱坞原则(不要打电话给我们,我们会打电话给您)。

但是,它稍微先进一点,并且需要更多“接线”而无需框架。因此,如果依赖项注入对您来说太复杂,请使用单例注册表而不是一堆全局变量。


所以当我将我的sqlQuery类设置为会话时,因为它可以扩展,所以我会全局访问数据库连接connect_pdo
ThomasK 2012年

7

我最近自己一个人来回答类似的问题。如果有人感兴趣,这就是我所做的:

<?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 */);

以及类型提示(如果您正在使用它来(\ 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对象的创建成本稍高,因此使其更加优化。这是一个透明的类,或称为Ghost的一种形式,即惰性加载。您可以将$ DB视为普通的PDO实例,将其传递过来,执行相同的操作,等等。


这就是所谓的“装饰器模式”
Yang

0
$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();
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.