web-dev-qa-db-ja.com

PDO接続を適切にセットアップする方法

データベースへの接続に関する質問が時々表示されます。
ほとんどの答えは私がやる方法ではありません。そうでないと、答えが正しく得られないかもしれません。とにかく;私はそれを行う方法が私のために働くので、私はそれについて考えたことがない。

しかし、これはおかしな考えです。たぶん私はこれをすべて間違ってやっている、そしてそれが事実なら。 PHPとPDOを使用してMySQLデータベースに適切に接続し、簡単にアクセスできるようにする方法を知りたいです。

これが私がそれをやっている方法です:

最初に、ここに私のファイル構造があります(stripped down)

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
他のクラスがextends this one ...

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を学習し、mysqlの代わりにPDOを使用し始めて以来、大幅な改善の余地があると考えています。
だから私は、初心者向けのチュートリアルをいくつか見て、さまざまなものを試しました...

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)

sqlQuery-classの中にextends my connect_pdo-classがあり、getAreaNameというパブリック関数がありますデータベースへのリクエストを処理します。
かなりきれいだと思います。

チャームのように動作します
それは基本的に私がやっていることです。
また、クラス内からではなくDBから何かを取得する必要があるときはいつでも、次のようなことを行います。

$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内の変数に入れたので、それを参照するだけでいいのです。できます。期待した結果が得られます...

しかし、それにもかかわらず。私がここにいるのかどうか教えてもらえたら本当にありがたいです。代わりにすべきこと、改善のために変更できる、または変更すべき領域など...

私は学びたいです...

91
ThomasK

目標

私が見るように、この場合の目的は2つあります:

  • データベースごとに単一/再利用可能な接続を作成および維持する
  • 接続が適切に設定されていることを確認してください

解決

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

}

この方法では、必要な場合にのみ接続が作成されるようにする、集中化された構造を使用できます。また、単体テストとメンテナンスのプロセスがはるかに簡単になります。

この場合のプロバイダーは、bootstrapステージのどこかにあります。このアプローチは、DBへの接続に使用する構成を定義する明確な場所も提供します。

これは非常に単純化された例であることに注意してください。また、次の2つのビデオを見ることもできます。

また、PDOの使用について 適切なチュートリアル を読むことを強くお勧めします(オンラインで悪いチュートリアルのログがあります)。

103
tereško

$_SESSIONを使用してDB接続にグローバルにアクセスしないことをお勧めします。

いくつかのことのいずれかを実行できます(最悪から最高プラクティスの順):

  • 関数とクラス内で$dbhを使用してglobal $dbhにアクセスします
  • シングルトンレジストリを使用し、次のようにグローバルにアクセスします。

    $registry = MyRegistry::getInstance();
    $dbh = $registry->getDbh();
    
  • 次のように、データベースハンドラを必要なクラスに挿入します。

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

最後のものを強くお勧めします。これは、依存性注入(DI)、制御の反転(IoC)、または単にハリウッドの原理(私たちを呼ばないで、あなたを呼ぶ)として知られています。

ただし、それはもう少し高度であり、フレームワークなしでより多くの「配線」が必要です。したがって、依存性の注入が複雑すぎる場合は、大量のグローバル変数の代わりにシングルトンレジストリを使用します。

23
Ian Unruh

私は最近、自分で同様の回答/質問に来ました。誰かが興味を持っている場合のために、これは私がやったことです:

<?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 と呼ばれる Lazy Loading の形式です。 $ DBを通常のPDOインスタンスとして扱い、渡したり、同じ操作を行ったりすることができます。

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

または http://ask.hcig.co.za/?p=179 を読んでください

0
hi-code