Fonksiyonları PDO try-catch kullanımı

2 Cevap php

Benim gelecekteki webapp tüm PDO kullanarak düşünüyorum. Şu anda (SO şimdiye kadar öğrendiklerinizi kullanarak), ne veritabanı bağlantısı işlemek için sitemde var böyle bir Singleton sınıf:

class DB {

    private static $instance = NULL;
    private static $dsn      = "mysql:host=localhost;dbname=mydatabase;";
    private static $db_user  = 'root';
    private static $db_pass  = '0O0ooIl1';

    private function __construct() 
    {

    }
    private function __clone()
    {

    }	
    public static function getInstance() {

	    if (!self::$instance)
		{			
		    self::$instance = new PDO(self::$dsn, self::$db_user, self::$db_pass);
		    self::$instance-> setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
		}
	    return self::$instance;
    }
}

ve içerik-özel fonksiyonlara sahip başka bir dosya (functions.php) tam olarak bu gibi arıyorum:

function get_recent_activities ()
{    
    try
    {    
    	$db = DB::getInstance();
        // --prepare and execute query here, fetch the result--
    	return $my_list_of_recent_activities;
    }
    catch (PDOException $e)
    {
    	return "some fail-messages";
    }
}
...

Ben fonksiyonları tüm try .. catch kısmını tekrarlamak zorundayız yani.

Benim sorular şunlardır:

  1. Bunu nasıl daha verimli yapmak gerekir? (Örn. tüm işlevlerde try..catch tekrarlamak zorunda, ve her biri farklı "fail-mesajı" dönmek için henüz hala mümkün değil)
  2. Bu zaten iyi bir uygulama mı? Ben bu yüzden (şimdi olduğu gibi), PDO ve OOP (hala çok daha fazla bilgi için) hala yeniyim, ben gerçekten orada geliştirilebilir herhangi dezavantajları veya şeyleri göremiyorum.

Bu belirsiz ya da çok uzun görünüyor üzgünüm. Şimdiden teşekkürler.

2 Cevap

Sizin uygulama gayet iyi olduğunu ve bir çok amaç için çok iyi çalışacağız.

Bir try / catch bloğu içinde her sorgu koymak için gerekli değildir, ve aslında çoğu durumda aslında istemiyorum. Bunun nedeni, bir sorgu, bir özel durum oluşturur, eğer bir sözdizimi hatası veya bir veritabanı sorunu gibi ölümcül bir sorunun sonucudur, ve bu yapmanız her sorgu ile muhasebe gereken konular değil olmasıdır.

Örneğin:

try {
    $rs = $db->prepare('SELECT * FROM foo');
    $rs->execute();
    $foo = $rs->fetchAll();
} catch (Exception $e) {
    die("Oh noes! There's an error in the query!");
}

Burada sorgusu iş ya düzgün ya da hiç çalışacaktır. Hiç işe olmaz koşullar hiç bir üretim sistemi üzerinde herhangi bir düzenlilik meydana olmamalı, bu yüzden onlar için burada kontrol etmelisiniz koşullar değiliz. Aksi takdirde, kullanıcıların asla değişmeyecek bir hata olsun, çünkü, aslında ters olduğunu ve bir sorun olduğunda sizi uyaracak bir istisna mesajı alamadım.

Bunun yerine, sadece bu yaz:

$rs = $db->prepare('SELECT * FROM foo');
$rs->execute();
$foo = $rs->fetchAll();

In general, the only time that you'll want to catch and handle a query exception is when you want to do something else if the query fails. Örneğin:

// We're handling a file upload here.
try {
    $rs = $db->prepare('INSERT INTO files (fileID, filename) VALUES (?, ?)');
    $rs->execute(array(1234, '/var/tmp/file1234.txt'));
} catch (Exception $e) {
    unlink('/var/tmp/file1234.txt');
    throw $e;
}

Siz günlükleri veya üretim ortamında oluşan veritabanı hataları size bildirir ve kullanıcıların yerine istisna iz dost bir hata mesajı görüntüler basit bir istisna işleyici yazmak isteyeceksiniz. Bunu nasıl hakkında bilgi için http://www.php.net/set-exception-handler bakın.

Burada uyarılar bir çift vardır:

  • Bu kod, veritabanı günlüğü ve veritabanı yapılandırma yönetimi olarak dikkate birkaç eski konuları alacak yazılır.
  • Ben kesinlikle kendi bina önce varolan bir çözümü bakmak tavsiye ederim. Onlar, çok büyüksün, vb öğrenmek için çok fazla zaman gerektirir, ancak, çünkü varolan bir çerçeveyi veya kitaplığı kullanmak istemiyorum dışarı başladığınızda bir sürü insan kendilerini düşünüyorum bu insanlardan biri sonra ben Ben bir çerçeveye taşımak için benim özel çerçeve ve sarıcı sınıflar gidiyorum ısrarla yeterli devlet olamaz. Ben Zend geçmek için arıyorum ama mükemmel bir seçenek vardır.

Oh, bu nokta bir sorguları için istisna işleme işlemek için tek bir işlev kaydırmak nasıl gösterir işaret olmalıdır. Ben sorgudan yığın izleme bana sorun hata ayıklama ve bunu düzeltmek için gereken tüm bilgileri verir, çünkü artık hemen hemen her yerde catch blokları denemek yazmayın.

İşte benim şimdiki PDO sarıcı sınıf uygulamasıdır:

class DB extends PDO 
{
    // Allows implementation of the singleton pattern -- ndg 5/24/2008
    private static $instance;

    // Public static variables for configuring the DB class for a particular database -- ndg 6/16/2008
    public static $error_table;
    public static $host_name;
    public static $db_name;
    public static $username;
    public static $password;
    public static $driver_options;
    public static $db_config_path;



    function __construct($dsn="", $username="", $password="", $driver_options=array()) 
    {
    	if(isset(self::$db_config_path))
    	{
    		try 
    		{
    			if(!require_once self::$db_config_path)
    			{
    				throw new error('Failed to require file: ' . self::$db_config_path); 
    			}
    		} 
    		catch(error $e) 
    		{
    			$e->emailAdmin();
    		}
    	}
    	elseif(isset($_ENV['DB']))
    	{
    		self::$db_config_path = 'config.db.php';

    		try 
    		{
    			if(!require_once self::$db_config_path)
    			{
    				throw new error('Failed to require file: ' . self::$db_config_path); 
    			}
    		} 
    		catch(error $e) 
    		{
    			$e->emailAdmin();
    		}
    	}

    	parent::__construct("mysql:host=" . self::$host_name . ";dbname=" .self::$db_name, self::$username, self::$password, self::$driver_options);
    	$this->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    	$this->setAttribute(PDO::ATTR_STATEMENT_CLASS, array('QueryStatement', array($this)));

    	if(!isset(self::$error_table))
    	{
    		self::$error_table = 'errorlog_rtab';
    	}
    }

    /**
     * Return a DB Connection Object
     *
     * @return DB
     */
    public static function connect()
    {

        // New PDO Connection to be used in NEW development and MAINTENANCE development
        try 
        {
        	if(!isset(self::$instance))
        	{	
        		if(!self::$instance =  new DB())
        		{
        			throw new error('PDO DB Connection failed with error: ' . self::errorInfo());
        		}
        	}

        	return self::$instance;
        }
        catch(error $e)
        {
        	$e->printErrMsg();
        }
    }

    /**
     * Returns a QueryBuilder object which can be used to build dynamic queries
     *
     * @return QueryBuilder
     * 
     */
    public function createQuery()
    {
        return new QueryBuilder();
    }

    public function executeStatement($statement, $params = null, $FETCH_MODE = null)
    {
        if($FETCH_MODE == 'scalar')
        {
        	return $this->executeScalar($statement, $params);	
        }


        try {
        	try {
    	    	if(!empty($params))
    	    	{
    	    		$stmt = $this->prepare($statement);
    	    		$stmt->execute($params);
    	    	}
    	    	else 
    	    	{
    				$stmt = $this->query($statement);
    	    	}
        	}
        	catch(PDOException $pdo_error)
        	{
        		throw new error("Failed to execute query:\n" . $statement . "\nUsing Parameters:\n" . print_r($params, true) . "\nWith Error:\n" . $pdo_error->getMessage());
        	}
        }
        catch(error $e)
        {
        	$this->logDBError($e);
        	$e->emailAdmin();
        	return false;
        }

    	try 
    	{
    		if($FETCH_MODE == 'all')
    		{
    			$tmp =  $stmt->fetchAll();
    		}
    		elseif($FETCH_MODE == 'column')
    		{
    			$arr = $stmt->fetchAll();

    			foreach($arr as $key => $val)
    			{
    				foreach($val as $var => $value)
    				{
    					$tmp[] = $value;
    				}
    			}			
    		}
    		elseif($FETCH_MODE == 'row') 
    		{
    			$tmp =  $stmt->fetch();
    		}
    		elseif(empty($FETCH_MODE))
    		{
    			return true;
    		}
    	}
    	catch(PDOException $pdoError)
    	{
    		return true;
    	}

        $stmt->closeCursor();

        return $tmp;

    }

    public function executeScalar($statement, $params = null)
    {
        $stmt = $this->prepare($statement);

        if(!empty($this->bound_params) && empty($params))
        {
        	$params = $this->bound_params;
        }

        try {
        	try {
    	    	if(!empty($params))
    	    	{
    	    		$stmt->execute($params);
    	    	}
    	    	else 
    	    	{
    					$stmt = $this->query($statement);
    	    	}
        	}
        	catch(PDOException $pdo_error)
        	{
        		throw new error("Failed to execute query:\n" . $statement . "\nUsing Parameters:\n" . print_r($params, true) . "\nWith Error:\n" . $pdo_error->getMessage());
        	}
        }
        catch(error $e)
        {
        	$this->logDBError($e);
        	$e->emailAdmin();
        }

        $count = $stmt->fetchColumn();

        $stmt->closeCursor();

        //echo $count;
        return $count;  	
    }

    protected function logDBError($e)
    {
        $error = $e->getErrorReport();

        $sql = "
        INSERT INTO " . self::$error_table . " (message, time_date) 
        VALUES (:error, NOW())";

        $this->executeStatement($sql, array(':error' => $error));
    }
}

class QueryStatement extends PDOStatement 
{
    public $conn;

    protected function __construct() 
    {
        $this->conn = DB::connect();
        $this->setFetchMode(PDO::FETCH_ASSOC);
    }

    public function execute($bound_params = null)
    {
    	return parent::execute($bound_params);  		
    }
}