93

ときどき、データベースへの接続に関する質問を目にします。
ほとんどの回答は私のやり方ではありません。または、正しく回答できない可能性があります。ともかく; 自分のやり方がうまくいくので、それについて考えたことはありません。

しかし、これはクレイジーな考えです。たぶん、私はこれをすべて間違っています。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プロパティをオーバーライドし、サイトのその他のグローバル構成を行うだけです

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 の学習を開始し、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)

my -class、 which my sqlQuery-classの内部には、データベースへリクエストを処理するパブリック関数が呼び出されています。 かなりきれいだと思います。extendsconnect_pdogetAreaName

魔法のように機能する
ので、基本的にはそうしています。
また、クラス内以外から 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内の変数に入れたので、それを参照するだけで準備完了です。できます。期待通りの結果が得られました...

しかし、それにもかかわらず。私がここから離れている場合は、教えていただければ幸いです。代わりに何をすべきか、改善のために変更できる、または変更する必要がある領域など...

私は学びたいと思っています...

4

5 に答える 5

106

目標

私が見ているように、この場合のあなたの目的は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 );
    }

}

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

この場合のプロバイダーは、ブートストラップ段階のどこかにあります。このアプローチにより、DB への接続に使用する構成を定義する場所も明確になります。

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

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

于 2012-07-06T21:09:30.870 に答える
24

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

いくつかのことのいずれかを行うことができます (最悪からベストプラクティスへの順序で):

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

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

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

ラストを強くお勧めします。これは、依存性注入 (DI)、制御の反転 (IoC)、または単にハリウッドの原則 (電話しないでください。電話します) として知られています。

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

于 2012-07-06T20:48:49.760 に答える
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();
}
于 2014-09-29T11:51:45.720 に答える
0

セットアップにはいくつかの基本的な欠陥があります。

  1. このconfigure.phpファイルは Web サーバーのドキュメント ルートにあるべきではありません。サーバーの構成に誤りがあると、資格情報が公開される可能性があります。自分には起こらないと思うかもしれませんが、それは取る必要のないリスクです。クラスもそこにあるべきではありません...これはそれほど重要ではありませんが、公開する必要がないものは公開すべきではありません。
  2. 特に大規模なプロジェクトで作業している場合を除き、「初期化」ディレクトリは必要ありません。1 つの大きなファイルを読み込むと、同じ内容の小さなファイルを 10 個読み込むよりも約 10 倍速くなります。これは、プロジェクトが大きくなるにつれて大きくなる傾向があり、PHP サイトの速度が大幅に低下する可能性があります。
  3. 実際に必要でない限り、ロードしないようにしてください。たとえば、実際に必要でない限り、PDO に接続しないでください。session_start()実際にセッションに読み書きしませんか。クラスのインスタンスを作成しない限り、クラス定義ファイルを含めないでください。接続できる数には制限があります。また、セッションなどの API は、同じリソースを使用している他のユーザーのコード実行を一時停止できる「ロック」を確立します。
  4. 私の知る限り、あなたは Composer を使用していません。あなたはそれを使うべきです-それはあなた自身のコードとサードパーティの依存関係の両方にとって非常に簡単になります.

これは、私が中規模のプロジェクトで使用するものと似た、私が提案したディレクトリ構造です。

init.php                Replaces public_html/initialize. Your PDO connection details
                        are held here.
classes/                Replaces public_html/classes
vendor/autoload.php     Your class autoload script generated using the
                        industry standard Composer command line tool
composer.json           The file where you describe how autoload.php
                        operates among other things. For example if you
                        don't use namespaces (maybe you should) it might be:
                        {"autoload": {"psr-4": { "": "classes/" }}}
public_html/index.php   Your landing page
public_html/other.php   Some other page
public_html/css/foobar.css ...and so on for all static resources

ファイルは次のinit.phpようになります。

date_default_timezone_set('Etc/UTC');

require 'vendor/autoload.php';

$pdoConnect = function() {
  static $pdo = false;
  if (!$pdo) {
    $pdo = new PDO('mysql:dbname=db;host=localhost', 'user', 'password');
    $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    $pdo->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_OBJ);
  }
  return $pdo;
};

// similar anonymous functions for session_start(), etc.

index.php次のようになります。

require '../init.php';

$pdo = $pdoConnect();

// go from there

other.php似ているかもしれませんが、おそらくデータベースに接続していないため、$pdoConnect を実行しません。

可能な限り、コードの大部分を classes ディレクトリに書き込む必要があります。index.php、 などは、other.phpできるだけ短く、甘くしてください。

于 2021-05-25T06:22:51.980 に答える