PDO bağlantısı nasıl doğru şekilde kurulur


92

Zaman zaman veritabanına bağlanmayla ilgili sorular görüyorum.
Çoğu cevap benim yaptığım yol değil, ya da cevapları doğru alamayabilirim. Neyse; Bunu hiç düşünmedim çünkü benim için işe yarıyor.

Ama işte çılgınca bir düşünce; Belki bunu tamamen yanlış yapıyorum ve eğer durum buysa; PHP ve PDO kullanarak bir MySQL veritabanına nasıl düzgün şekilde bağlanacağımı ve onu kolay erişilebilir hale getirmeyi gerçekten bilmek istiyorum.

İşte bunu nasıl yapıyorum:

Öncelikle, işte benim dosya yapım (soyulmuş) :

public_html/

* index.php  

* initialize/  
  -- load.initialize.php  
  -- configure.php  
  -- sessions.php   

index.php
En üstte var 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');

Sınıfları dahil etmenin daha iyi veya daha doğru bir yolu olduğunu biliyorum ama ne olduğunu hatırlayamıyorum. Henüz incelemeye vaktim olmadı, ama bence bir şeydi autoload. bunun gibi bir şey...

configure.php
Burada temel olarak bazı php.ini -properties'i geçersiz kılıyorum ve site için başka bir global konfigürasyon yapıyorum

connect.php
Bağlantıyı bir sınıfa koydum, böylece diğer sınıflar bunu genişletebilir ...

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

Burada, son zamanlarda OOP öğrenmeye başladığımdan ve mysql yerine PDO kullanmaya başladığımdan bu yana büyük gelişme için yer olduğuna inanıyorum.
Bu yüzden yeni başlayanlara yönelik birkaç öğreticiyi takip ettim ve farklı şeyler denedim ...

sessions.php
Normal oturumları işlemenin yanı sıra, bazı sınıfları aşağıdaki gibi bir oturumda başlatıyorum:

if (!isset($_SESSION['sqlQuery'])){
    session_start();
    $_SESSION['sqlQuery'] = new sqlQuery();
}

Bu şekilde bu sınıf her yerde mevcuttur. Bu iyi bir uygulama olmayabilir (?) ...
Her neyse, bu yaklaşımın her yerden yapmama izin verdiği şey:

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

Benim İçinde sqlQuery- sınıfta , extendsbenim connect_pdo- sınıfta , ben olarak adlandırılan bir kamu fonksiyonu var getAreaNamebenim veritabanına isteği işler.
Bence oldukça temiz.

Bir cazibe gibi çalışıyor
Yani temelde böyle yapıyorum.
Ayrıca, ne zaman bir sınıf içinde olmayan DB'mden bir şey almam gerektiğinde, buna benzer bir şey yapıyorum:

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

Bağlantıyı connect_pdo.php içindeki bir değişkene koyduğum için , sadece ona atıfta bulundum ve gitmekte fayda var. İşe yarıyor. Beklediğim sonuçları alıyorum ...

Ama bundan bağımsız olarak; Buradan uzaklaşırsam bana söylerseniz çok sevinirim. Bunun yerine ne yapmalıyım, iyileştirmek için değiştirebileceğim veya değiştirmem gereken alanlar vb ...

Öğrenmeye hevesliyim ...


9
Her bir dosyayı aynı anda uygulamanıza eklemek yerine bir otomatik yükleyici kullanmalısınız .
lusitanian

4
Bu soru muhtemelen Kod İncelemesinde
Madara's Ghost

Yanıtlar:


105

Amaç

Gördüğüm kadarıyla, bu durumda amacınız iki yönlü:

  • veritabanı başına tek / yeniden kullanılabilir bir bağlantı oluşturun ve koruyun
  • bağlantının doğru şekilde kurulduğundan emin olun

Çözüm

PDO bağlantısı için hem anonim işlevi hem de fabrika modelini kullanmanızı tavsiye ederim. Bunun kullanımı şöyle görünür:

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

Sonra aynı dosyada farklı bir dosyada veya daha düşük bir dosyada:

$something = $factory->create('Something');
$foobar = $factory->create('Foobar');

Fabrikanın kendisi şöyle görünmeli:

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

}

Bu yol, bağlantının yalnızca gerektiğinde oluşturulmasını sağlayan merkezi bir yapıya sahip olmanızı sağlar. Ayrıca, birim testi ve bakım sürecini çok daha kolay hale getirecektir.

Bu durumda sağlayıcı, önyükleme aşamasında bir yerde bulunabilir. Bu yaklaşım aynı zamanda DB'ye bağlanmak için kullanacağınız konfigürasyonu nerede tanımlayacağınız konusunda net bir yer verecektir.

Bunun son derece basitleştirilmiş bir örnek olduğunu unutmayın . Aşağıdaki iki videoyu izlemekten de yararlanabilirsiniz:

Ayrıca, PDO kullanımı hakkında uygun bir öğretici okumanızı şiddetle tavsiye ederim (çevrimiçi olarak kötü bir eğitim kaydı vardır).


3
PHP5.3 bile EOL'ye yaklaştığından beri. Güncel olmayan PHP sürümlerine sahip sitelerin çoğu aslında sadece Wordpress için ucuz barındırmadır. 5.3 öncesi ortamların mesleki gelişim üzerindeki etkisi (bu tür snippet'lerden fayda sağlayacak bir tür) tahminime göre ihmal edilebilir.
tereško

5
@thelolcat Sana katılıyorum. Bu ise aşağı yukarı aynı cevap. Tabii bunun tamamen farklı olduğu gerçeğini görmüyorsanız.
PeeHaa

1
@thelolcat, sonra bağımlılık enjeksiyonunun ne olduğunu öğrenmelisiniz . Kendini utandırmaya devam etmek yerine. Yeterince tuhaf bir şekilde, yukarıdaki gönderideki ikinci video ( "Şeylere Bakma" başlıklı ) aslında DI'nın ne olduğunu ve nasıl kullanılacağını açıkladı ... ama elbette bu kadar önemsiz şeyler için çok gelişmişsiniz.
tereško

2
Bu eski bir cevap, ancak iyi bir cevap - ve sonunda Mysql pdo ile harika bir bağlantı
Strawberry

1
@teecee önce PDO'nun nasıl kullanılacağını öğrenerek başlamalısınız. Bu öğreticiyi tavsiye ederim: wiki.hashphp.org/PDO_Tutorial_for_MySQL_Developers , çünkü tam olarak PDO'dan geçiş yapmak isteyen insanlar için yapıldı mysql_*. Daha sonra geri dönüp, halihazırda PDO kullanan, ancak birden çok sınıf arasında DB bağlantısını paylaşmanın bir yolunu arayanlara yönelik bu çözümlere bakabilirsiniz.
tereško

24

$_SESSIONDB bağlantınıza küresel olarak erişmek için kullanmamanızı öneririm .

Birkaç şeyden birini yapabilirsiniz ( en kötüden en iyi uygulamalara doğru sırayla ):

  • İşlevlerinizin ve sınıflarınızın içini $dbhkullanarak erişinglobal $dbh
  • Tek bir kayıt defteri kullanın ve buna küresel olarak erişin, örneğin:

    $registry = MyRegistry::getInstance();
    $dbh = $registry->getDbh();
    
  • Veritabanı işleyicisini ihtiyacı olan sınıflara şu şekilde enjekte edin:

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

Sonuncusunu şiddetle tavsiye ederim. Bağımlılık enjeksiyonu (DI), kontrolün tersine çevrilmesi (IoC) veya kısaca Hollywood prensibi (Bizi arama, sizi arayacağız) olarak bilinir.

Ancak, biraz daha gelişmiştir ve çerçeve olmadan daha fazla "kablolama" gerektirir. Bu nedenle, bağımlılık ekleme sizin için çok karmaşıksa, bir grup genel değişken yerine tek bir kayıt defteri kullanın.


Yani, sqlQuery-class'ımı genişlediğinden beri oturuma ayarladığımda global olarak db bağlantıma erişiyorum connect_pdo?
ThomasK

7

Geçenlerde benzer bir cevaba / soruya kendi başıma geldim. Birinin ilgilenmesi durumunda yaptığım şey buydu:

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

Onu aramak için sadece bu hattı değiştirmeniz gerekir:

$DB = new \Library\PDO(/* normal arguments */);

Ve (\ Kitaplık \ PDO $ DB) için kullanıyorsanız tip ipucu.

Gerçekten hem kabul edilen yanıta hem de sizin yanıtınıza benziyor; ancak önemli bir avantajı var. Bu kodu düşünün:

$DB = new \Library\PDO( /* args */ );

$STH = $DB->prepare("SELECT * FROM users WHERE user = ?");
$STH->execute(array(25));
$User = $STH->fetch();

Normal PDO gibi görünse de ( \Library\yalnızca bununla değişir ), siz ilk yöntemi çağırana kadar, hangisi olursa olsun, aslında nesneyi başlatmaz. PDO nesnesi oluşturma biraz pahalı olduğundan, bu onu daha optimize hale getirir. Şeffaf bir sınıf veya Hayalet denen , bir Tembel Yükleme biçimi . $ DB'yi normal bir PDO örneği olarak ele alabilir, etrafından dolaştırabilir, aynı işlemleri yaparak vb.


Buna "Dekoratör kalıbı" denir
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();
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.