2011-10-01 18 views
6

Usando PDO::setAttribute, ¿cómo proporciono el nombre de clase al establecer PDO::ATTR_DEFAULT_FETCH_MODE en PDO::FETCH_CLASS?En PHP, ¿cómo configuro la clase de recuperación de PDO predeterminada?

Este es el código que estoy utilizando .. Me gustaría configurarlo para todos mis filas se devuelven como una instancia de DB_Row:

class DB_Row extends ArrayObject {} 

$db = new PDO('mysql:dbname=example;host=localhost', 'user', 'pass'); 
$db->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_CLASS); 

$stmt = $db->query("SELECT * FROM `table` WHERE `id` = 1;"); 

$row = $stmt->fetch(); // I want a DB_Row by default! 

El código anterior da como resultado una PDOException ya que la clase DB_Row nombre no fue asignado

Fatal error: Uncaught exception 'PDOException' with message 'SQLSTATE[HY000]: General error: No fetch class specified 

¿Qué debo hacer al respecto?

Gracias de antemano ..

SOLUCIÓN : que utilizan respuesta fireeyedboy 's. Se trabajó el mejor para mi situación como ya estaba extendiendo PDOStatement con fines de explotación forestal ...

class DB extends PDO { 
    public function __construct($host = null, $user = null, $pass = null, $db = null) { 
     try { 
      parent::__construct('mysql:dbname=' . $name .';host=' . $host, $user, $pass); 
      $this->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); 
      $this->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_CLASS); 
      $this->setAttribute(PDO::ATTR_STATEMENT_CLASS, array('DB_Query', array('DB_Row'))); 
     } catch (PDOException $e) { 
      die('Database Error'); 
     } 
    } 
} 

class DB_Query extends PDOStatement { 
    private $class; 
    protected function __construct ($class = 'DB_Row') { 
     $this->class = $class; 
     $this->setFetchMode(PDO::FETCH_CLASS, $this->class); 
    } 
} 

class DB_Row extends ArrayObject { 
    public function __set($name, $val) { 
     $this[$name] = $val; 
    } 
    public function __get($name) { 
     return $this[$name]; 
    } 
} 

Respuesta

3

Otro tipo de truco sería extender PDOStatement, anular sus métodos de búsqueda y dejar que su instancia PDO la use como la clase de instrucción predeterminada.

Como ejemplo voy a demostrar anulando fetch() y dejar fetchAll() y lo que tienes hasta que, si quieres ir a esta ruta:

class Db_Row 
{ 
} 

class PDOStatementWithClass 
    extends PDOStatement 
{ 
    private $fetch_class; 

    // PHP complained when I tried to make this public 
    protected function __construct($fetch_class = 'StdClass') 
    { 
     // internally set the fetch class for later use 
     $this->fetch_class = $fetch_class; 
    } 

    // let $fetch_style default to PDO::FETCH_CLASS in stead of PDO::FETCH_BOTH 
    public function fetch($fetch_style = PDO::FETCH_CLASS, $cursor_orientation = PDO::FETCH_ORI_NEXT, $cursor_offset = 0) 
    { 
     // make sure we're really dealing with the correct fetch style 
     if($fetch_style == PDO::FETCH_CLASS) 
     { 
      // then automatically set the fetch mode of this statement 
      parent::setFetchMode($fetch_style, $this->fetch_class); 
     } 

     // go ahead and fetch, we should be good now 
     return parent::fetch($fetch_style, $cursor_orientation, $cursor_offset); 
    } 
} 

$db = new PDO(/* etc... */); 
// set default fetch mode to FETCH_CLASS 
$db->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_CLASS); 
// override what statement class to use, and provide constructor arguments (found out by trial and error) 
$db->setAttribute(PDO::ATTR_STATEMENT_CLASS, array('PDOStatementWithClass', array('Db_Row'))); 

Esto tiene la ventaja añadida de que' Solo tendrá que definir su PDO::FETCH_CLASS una vez en su aplicación, y no en cada consulta.


1) Estoy sorprendido de que PHP no se haya quejado sobre la anulación de la firma del método por cierto.

+0

¡Gracias por eso! Este es el método que utilicé. La razón principal fue porque no quería definir el nombre de clase en todas mis consultas. En lugar de anular la búsqueda, acabo de agregar esto al constructo: $ this-> setFetchMode (PDO :: FETCH_CLASS, $ this-> class); – McHerbie

5

creo que debe devolver una instancia stdClass por lo que este sería un error - pero tendría que mirar hacia arriba en el código para verificar lo hará si no hay una respuesta aceptada hasta entonces.

Lo que funcionará es usar PDO :: FETCH_CLASS | PDO :: FETCH_CLASSTYPE y luego proporcione un nombre de clase como primera columna. Si bien este es un truco:

$db->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_CLASS | PDO::FETCH_CLASSTYPE); 

$stmt = $db->query("SELECT 'classname', * FROM `table` WHERE `id` = 1;"); 

EDITAR: Como prometí aquí el código. El código relevante está aquí http://lxr.php.net/xref/PHP_5_4/ext/pdo/pdo_stmt.c#940 Por lo tanto, establecer el uso de fetch() solo es posible con FETCH_CLASSTYPE. La alternativa es usar PDOStatement :: fetchObject()

+0

Gracias @johanne! Este método funciona bien, aunque es engorroso para mí actualizar todas las consultas utilizadas. Sería bueno para PDO permitir la clase definida fuera de la estructura db. Especialmente porque en la mayoría de los casos planeo usar siempre la misma clase. – McHerbie