Una de las máximas prioridades en una aplicación PHP que haga uso de una base de datos, es la organización y eficiencia del código para evitar consumo innecesario de memoria, esto es bien sabido por cualquier programador. Pero ¿qué hay de la separación del código de lógica y el de la base de datos?
El patrón Modelo-Vista-Controlador nos puede ser de gran utilidad ya que separa la lógica (controladores) de scripts que acceden y relacionan las tablas de un base de datos (modelos) y de la interfaz gráfica (vistas). Pero en ocasiones no necesitamos de tantas capas de abstracción y decidimos programar todo revuelto. Aún así, utilizar una clase para los accesos a la base de datos nos es de gran ayuda para aquello de la organización del código.
La clase que a continuación propongo utiliza un patrón llamado Singleton. Este patrón obliga a instanciar unicamente una vez la clase para evitar 2 o más conexiones simultáneas. La clase contiene métodos para ejecutar sentencias SQL, cargar resultados en forma de objetos, ver el número de consultas totales etc.
<?php
class DataBase {
private $conexion;
private $resource;
private $sql;
public static $queries;
private static $_singleton;
public static function getInstance(){
if (is_null (self::$_singleton)) {
self::$_singleton = new DataBase();
}
return self::$_singleton;
}
private function __construct(){
$this->conexion = @mysql_connect('localhost', 'db_user', 'db_password'));
mysql_select_db('database_name', $this->conexion);
$this->queries = 0;
$this->resource = null;
}
public function execute(){
if(!($this->resource = mysql_query($this->sql, $this->conexion))){
return null;
}
$this->queries++;
return $this->resource;
}
public function alter(){
if(!($this->resource = mysql_query($this->sql, $this->conexion))){
return false;
}
return true;
}
public function loadObjectList(){
if (!($cur = $this->execute())){
return null;
}
$array = array();
while ($row = @mysql_fetch_object($cur)){
$array[] = $row;
}
return $array;
}
public function setQuery($sql){
if(empty($sql)){
return false;
}
$this->sql = $sql;
return true;
}
public function freeResults(){
@mysql_free_result($this->resource);
return true;
}
public function loadObject(){
if ($cur = $this->execute()){
if ($object = mysql_fetch_object($cur)){
@mysql_free_result($cur);
return $object;
}
else {
return null;
}
}
else {
return false;
}
}
function __destruct(){
@mysql_free_result($this->resource);
@mysql_close($this->conexion);
}
}
?>
Si notamos, el constructor es privado. ¿Por qué? para asegurarnos de que la clase se instancie desde dentro de sí misma. Es decir, al ejecutar el método DataBase::getInstance() llamamos al constructor y creamos una única instancia de DataBase. Si volvemos a ejecutar ese método y la clase ya ha sido instanciada antes, entonces nos devolverá la instancia. Eso es el objetivo del patrón Singleton.
Veamos entonces como hacer una conexión, ejecutar una consulta y mostrar los resultados. Se asume que los parámetros de conexión como el host, el nombre de usuario y demás se especifican directamente en la clase.
// Hacemos la conexión
$db = DataBase::getInstance();
// Supongamos que tenemos una tabla de usuarios
// Hacemos la consulta:
$db->setQuery('SELECT `id`,`nombre`,`grupo` FROM `usuarios`');
// La ejecutamos y al mismo tiempo obtenemos un arreglo de objetos
// con los campos especificados en la consulta como propiedades.
$usuarios = $db->loadObjectList();
// Los imprimimos directamente en pantalla...
foreach($usuarios as $usuario){
echo 'ID: '.$usuario->id;
echo 'Nombre: '.$usuario->nombre;
echo 'Grupo: '.$usuario->grupo;
echo '<br />';
}
Y ahí tienen un pequeñísimo ejemplo de uso. Algunos métodos como el DataBase::loadObject o DataBase::loadObjectList fueron tomados de la API de Joomla. En fin, espero que les sea de utilidad.
Popularidad: 31%







17 de Abril de 2008
hola me ayudo mucho tu clase de php y databases gracias
12 de Junio de 2008
Dime esta bacan pero esta clase permite tambien ejecutar insert update y todo eso y si es como podria hacerlo..
13 de Junio de 2008
Es fácil:
$db = DataBase::getInstance(); $db->setQuery("INSERT INTO tabla VALUES ('','$nombre','$edad')"); if( $db->alter() ){ // se inserto... } else{ // no se inserto... }20 de Junio de 2008
Hola,
Soy un novato en esto de las clases con PHP, he copiado tal cual tu clase y luego copie en otro php el ejemplo de la consulta, el tema es que me esta dando un error en el foreach:
Warning: Invalid argument supplied for foreach() in C:\Servidor\Web\pruebaClases\query.php on line 24
y la linea 24 es la que dice :
foreach($usuarios as $usuario){
20 de Junio de 2008
Supongo que tienes creada una tabla llamada usuarios con esos 3 campos, y que tu tabla tiene más de un registro….
¿Verdad?
20 de Junio de 2008
Abel,
te pido mil disculpas soy tan distraido que me habia olvidado de escribir el nombre de mi base de datos, lo que estoy intentando es agregar los datos de nombre de base, usuario de base, password y servidor para que lo lea de un archivo para que quede parametrizado.
Te hago una consulta: ¿se usa leer estos datos de un archivo?
desde ya muchisimas gracias por tu aporte!!!
Pablo
20 de Junio de 2008
No, no se usa leer esos datos de un archivo, pero si asi lo quieres hacer, puedes usar un XML:
Solo tendrias que hacerle un parsing, y sacar los datos y usarlos para la conexion… lo cual me parece muy descabellado…. Creo que la mejor alternativa es declarar constantes dentro de la clase y asignarle esos valores…
Respondi bien tu pregunta o me fui por otro lado?
9 de Septiembre de 2008
hola utilize tu clase pero tengo un pequeño problema
Warning: Invalid argument supplied for foreach() in /var/www/html/cat/solicitudeq.php on line 37
solo que nada mas puse un campo en la consulta asi:
$db = DataBase::getInstance();
// Hacemos la consulta:
$db->setQuery(“SELECT id_equipo FROM CatalogoPrestamo WHERE disponible=’1′ and tipo=’L’ “);
$LAP= $db->loadObjectList();
foreach($x as $LAP)
{
echo ‘ID equipo: ‘.$LAP->id_equipo;
}
supongo que si sepuede utilizar con where vdd?
9 de Septiembre de 2008
Hola jesus, el problema está el foreach. La sintaxis del foreach es:
foreach( $arreglo_con_valores as $variable_individual){ }Tu pusiste: foreach($x as $LAP), y debe ser al revés:
foreach($LAP as $x){ echo 'ID equipo: '.$x->id_equipo; }9 de Septiembre de 2008
muchas gracias abel … no cheque la sintaxis… saludos.
solo otra pregunta: si se pueden hacer multiples consultas con la misma clase vdd? un ejemplo porfa?
9 de Septiembre de 2008
Claro, solo hay que estar modificando la propiedad $sql y como es privada hay que usar el método Database::setQuery($sql).
Así que antes de cada consulta hay que hacer el:
correspondiente.
9 de Septiembre de 2008
otra pregunta como se podria asignar, suponiendo que solo obtenga un registro unico de la consulta a una variable que no sea un arreglo o imprimirlo? por ejemplo algo asi:
$db = DataBase::getInstance();
$db->setQuery(“SELECT id_equipo FROM CatalogoPrestamo WHERE disponible=’1′ and tipo=’L’ “);
$LAP= $db->loadObjectList();
$var=LAP
echo $var;
9 de Septiembre de 2008
$db = DataBase::getInstance(); $db->setQuery(”SELECT id_equipo FROM CatalogoPrestamo WHERE disponible=’1′ and tipo=’L’ “); $LAP = $db->loadObjectList(); $var = $LAP[0]; echo $var->id_equipo;9 de Septiembre de 2008
muchas gracias de nuevo me fue de gran utilidad….
19 de Septiembre de 2008
Hola:
¿Y cómo sería el código para realizar un SQL tipo “Select count(*) from tabla” o “Select max(id) from tabla”?
Muchas gracias
19 de Septiembre de 2008
Creo que ya he arreglado con esto:
$db = DataBase::getInstance();
$db->setQuery(“select count(id) as TOTAL from operadores where op_name=’”.$nombre.”‘ and op_key=’”.$clave.”‘”);
$LAP = $db->loadObjectList();
$var = $LAP[0];
echo $var->TOTAL;
Si hay alguna manera más eficiente, por favor, indicarla.
Muchas gracias
6 de Noviembre de 2008
Hola,
gracias por la aportación, realmente útil. Me gustaría saber si tienes algo implementado para usar transacciones con esta clase.
Gracias!
13 de Noviembre de 2008
hola, tengo un problema con la clase, me esta generando un error si realizo un session_start() despues de hacer el llamado de ésta clase, como si generara una salida en la clase, el problema que tengo es que me es obligatorio llamar el session_start() despues de declarar la clase. este es el erro: Warning: session_start() [function.session-start]: Cannot send session cache limiter – headers already sent (output started at C:\AppServ\www\liquidador\core\database.php:82) in C:\AppServ\www\liquidador\index.php on line 3
30 de Deciembre de 2008
Y como seria usando el metodo
loadObject
Ese no lo explicas, pero si el loadObjectList.
Pienso en voz alta, en ultimas el objeto devuelto por loadObjectList es un array y podria imprimirse con print_r ..
es para verificar que si tiene valores….
bye
31 de Enero de 2009
Hola, estoy tratando de usar tu clase, pero no logro validar utilizando la funcion alter, siempre me indica que el valor false, puedes ayudarme?
5 de Febrero de 2009
hola que tal oye necesito una mega ayuda necesito crear un programa que me pida una contraseña y cuando la contraseña sea correcta pueda abrir otro programa, bueno ya tengo el programa dela contraseña pero el problema es que no se como hacer para que me abra el nuevo programa cuando la contraseña esta correcta por favor si alguien me puede ayudar les agradeceria su apoyo
5 de Marzo de 2009
public function _Transaction() {
mysql_disconnect($this->conexion);
}
public function begin() {
mysql_query(“BEGIN”, $this->conexion);
}
public function rollback() {
mysql_query(“ROLLBACK”, $this->conexion);
}
public function commit() {
mysql_query(“COMMIT”, $this->conexion);
}
7 de Marzo de 2009
Hola !!!
Me han mandado un trabajo de PHP con MYSQL.
Lo que me pide es que cuando me conecte a una BBDD cualquiera, que me muestre en una tabla() de html las tablas que tiene la BBDD. Cuando seleccione una tabla que me muestre los campos que tiene … y ademas que se pueda seleccionar varios campos para mostrarlos, un SUM, un MAX, un MIN, GROUP BY y ORDER BY.
Si puedes me gustaria que me ayudases !!!
Muchas gracias.
Atentamente Eduard.
17 de Marzo de 2009
Solamente quisiera agradecerte tu clase. Esto si es implementar POO con PHP!!!!
27 de Marzo de 2009
como uso el comentario de Kimi Brown ??????????????????????????????? hey admin te sabes el mail de el??
28 de Marzo de 2009
Sí, es brownkimi arroba yahoo punto com
3 de Abril de 2009
Tambien pueden utilizar, en vez de XML para la config, un simple PHP o si lo prefieren un JSON, tengo una clase para el trabajo con JSON. La cogi de la libreria de Ext JS,creo, no recuerdo bien.
Saludos
rafa
20 de Mayo de 2009
Hola, copie esta clase pero a la hora de ejecutarla en un script en modo local me da el siguiente error:
Parse error: syntax error, unexpected T_DNUMBER in D:\AppServ\www\lib\MySQL.php on line 3
Alguien sabe porque??
Saludos y si alguien puede decirme donde encontrar mas documentacion se lo agradeceria (estoy empezando en esto de POO para php)
26 de Mayo de 2009
Excelente tu clase amigo, pero que tal si se desea hacer una consulta a dos o mas BD del mismo gestor al mismo tiempo
9 de Junio de 2009
Que tal estoy haciendo una aplicacion necesito la conexion de MySql pero la verdad es que php no se nada estoy leyendo manueales y tutoriales solo quiero que me expliquen como puedo guardar la clase de arriba y como utilizar la de abajo en un boton para que me guarde los valores, no se si es xq estoy utilizando el IDE de NetBeams para php , la verdad es que yo programo en Java pero nunca lo e echo en php espero que alguien me pueda ayudar y gracias por la atencion..!!
ATT:
!!..CMDD..!!
14 de Junio de 2009
Me ha impresionado tu clase, pero tengo una duda, si yo quisiera implementar la funcion addslashes(), donde la implementaría, digamos que quiero consultar el usuario y la contraseña, ¿donde colocaria esta funcion o donde colocaria el respectivo codigo para evitar sql injection?
Otra cosa, ¿Será posible parametrizar tu clase para que no se conecte solamente con mysql sino tambien con oracle, postgress, access o sqlserver inclusive?
Quiero agradecerte y me quito el sombrero ante ti por que le veo una ran utilidad a la clase que has hecho. gracias….
2 de Septiembre de 2009
hola excelente clase, gracias me ha servido de mucho , tengo una duda mira porque en el metodo
public function loadObjectList(){
if (!($cur = $this->execute())){
return null;
}
$array = array();
while ($row = @mysql_fetch_object($cur)){
$array[] = $row;
}
return $array;
}
No pones la sentencia pra liberar recursos como si lo pones en
public function loadObject(){
if ($cur = $this->execute()){
if ($object = mysql_fetch_object($cur)){
@mysql_free_result($cur);
return $object;
}
else {
return null;
}
}
else {
return false;
}
}
OSEA ESTA LINEA – @mysql_free_result($cur); que a mi entender alli estas liberando los recurso de memoria noes asi? te agradeceria si me pudieras absolver esa duda
29 de Septiembre de 2009
Alguien sabe si esta clase, permite updates, commits y roolback(transacciones)?
13 de Noviembre de 2009
Hola Como estas, Como puedo hacer para que que me de un mensaje en una consulta, Me explico, quiero Validar un Usuario, si el usuario existe realizo una Acción y si no Existe Realizo otra.
algo muy parecido a lo que hiciste acá, pero para un select
$db = DataBase::getInstance();
$db->setQuery(“INSERT INTO tabla VALUES (”,’$nombre’,'$edad’)”);
if( $db->alter() ){
// se inserto…
}
else{
// no se inserto…
}
2 de Deciembre de 2009
Como puedo paginar el resultado obtenido. Alguien me puede ayudar?
2 de Deciembre de 2009
Un problema q se me dio cuando quise usar es:
————————-
Parse error: parse error, unexpected T_STRING, expecting T_OLD_FUNCTION or T_FUNCTION or T_VAR or ‘}’ in /home/content/p/e/r/…./mysql.class.php on line 5
—————————–
Nota: Estoy usando el PHP Version PHP Version 4.3.11, no se si tenga algo que ver… saludos
4 de Deciembre de 2009
@Ruben, si tiene mucho que ver tu versión de PHP, ese código es para PHP5. El 4.x no maneja modificadores de acceso (public, private, protected) entre otras diferencias…
7 de Deciembre de 2009
Soy principiante y estoy haciendo una aplicación en PHP y Mysql que es un inventario, pero se me esta dificultando relacionar registros entre tablas, podrian hacerme favor de enviarme un ejemplo resuelto.
Mi duda es por ejemplo: capturo 200 piezas cuando hago la salida se debe restar de esas 200 piezas y ademas dejar en alguna tabla el historial.
Gracias.
18 de Deciembre de 2009
Abel, si pudieras ayudarm, copie tal y como esta la clase y la guarde con el nombre de database.php de igual forma el ejemplo conectar.php al momento de compilar conectar.php, no responde la consulta; tengo la base de datos dbbiblioteca y la tabla usuarios con mas de 5 registros de esta forma
create table usuarios(
id int not null,
nombre char(80) not null,
primary key (id)
)
ENGINE = InnoDB;
y la clase de esta forma:
conexion = @mysql_connect(‘localhost’, ‘root’, ‘abcd’));
mysql_select_db(‘dbBiblioteca’, $this->conexion);
$this->queries = 0;
$this->resource = null;
}
public function execute(){
if(!($this->resource = mysql_query($this->sql, $this->conexion))){
return null;
}
$this->queries++;
return $this->resource;
}
public function alter(){
if(!($this->resource = mysql_query($this->sql, $this->conexion))){
return false;
}
return true;
}
public function loadObjectList(){
if (!($cur = $this->execute())){
return null;
}
$array = array();
while ($row = @mysql_fetch_object($cur)){
$array[] = $row;
}
return $array;
}
public function setQuery($sql){
if(empty($sql)){
return false;
}
$this->sql = $sql;
return true;
}
public function freeResults(){
@mysql_free_result($this->resource);
return true;
}
public function loadObject(){
if ($cur = $this->execute()){
if ($object = mysql_fetch_object($cur)){
@mysql_free_result($cur);
return $object;
}
else {
return null;
}
}
else {
return false;
}
}
function __destruct(){
@mysql_free_result($this->resource);
@mysql_close($this->conexion);
}
}
?>
el ejemplo de esta forma:
setQuery(‘SELECT `id`,`nombre` FROM `usuarios`’);
// La ejecutamos y al mismo tiempo obtenemos un arreglo de objetos
// con los campos especificados en la consulta como propiedades.
$usuarios = $db->loadObjectList();
// Los imprimimos directamente en pantalla…
foreach($usuarios as $usuario){
echo ‘ID: ‘.$usuario->id;
echo ‘Nombre: ‘.$usuario->nombre;
echo ”;
}
?>
PD: Uso mysql 5 y php 5 apache 2.2, no se cual es el error
18 de Deciembre de 2009
Sorry, el ejemplo conectar.php esta de la siguiente forma:
setQuery(‘SELECT `id`,`nombre` FROM `usuarios`’);
// La ejecutamos y al mismo tiempo obtenemos un arreglo de objetos
// con los campos especificados en la consulta como propiedades.
$usuarios = $db->loadObjectList();
// Los imprimimos directamente en pantalla…
foreach($usuarios as $usuario){
echo ‘ID: ‘.$usuario->id;
echo ‘Nombre: ‘.$usuario->nombre;
echo ”;
}
?>
Espero una respuesta pronta. Por favor, me urge. Gracias desde luego.
18 de Deciembre de 2009
Disculpa un error tras otro el ejemplo conectar es:
.setQuery(‘SELECT `id`,`nombre` FROM `usuarios`’);
// La ejecutamos y al mismo tiempo obtenemos un arreglo de objetos
// con los campos especificados en la consulta como propiedades.
$usuarios = $db->loadObjectList();
// Los imprimimos directamente en pantalla…
foreach($usuarios as $usuario){
echo ‘ID: ‘.$usuario->id;
echo ‘Nombre: ‘.$usuario->nombre;
echo ”;
}
?>
17 de Enero de 2010
He estado buscando código para manejar bases de datos y al final me quedo con el tuyo. Es simple, sencillo y fácil.
Le añado el apunte para manejar transacciones que hay en uno de los comentarios.
Muchas gracias
9 de Febrero de 2010
Hola Abel, muy interesante el patrón singletón, pero veo que este es estrictamente enfocado a mysql como gestor de base de datos, se podria adaptar para oracle o sql server ??
1 de Marzo de 2010
Hola!, muy buen aporte pero quisiera saber como haria para instanciar dos base de dator para poder usar dos conexiones.
9 de Abril de 2010
Buenas, una pregunta, tambien se puede usar para borrar registros y actualizar?. porque no veo esa implementacion en la clase
12 de Abril de 2010
Puedes implementar los métodos ahí mismo, o puedes extender la clase, o puedes usar:
DataBase::setQuery($update_o_delete_query);
DataBase::alter():
22 de Abril de 2010
ola q tal !
es muy buena class …
pero … como le puedo hacer para q siempre no tenga q poner
” $db = DataBase::getinstance(); ” , al inicio de cada consulta.
24 de Abril de 2010
Hola a todos, me sirvio mucho esta clase, esta bueno; y como aporte quisiera responder algunas de las preguntas que quedaron flotando.
1)
24 de Abril de 2010
Hola a todos, me sirvio mucho esta clase, esta bueno; y como aporte quisiera responder algunas de las preguntas que quedaron flotando.
1) A la pregunta de Jesus y Hely sobre como recepcionar el dato de la consulta cuando esta solo tiene un registro.
Rpta: Para eso esta loadObject, que te retorna un objeto, a diferencia de loadObjectList() que retorna un array de objetos (Por eso utiliza foreach para que recorra todos los elementos de array) y “sql_free_result” solo sirve para liberar recursos al servidor, aunque en las ultimas versiones de Mysql esto se hace automaticamente. Entonces ¿Donde utilizar loadObject?:
Cuando la consulta me devuelve un registro. Ejm:
$db = DataBase::getInstance();
$db->setQuery(“SELECT nombre FROM clientes WHERE id_cliente=’201054′ “);
$row=$db->loadObject(); // retorna un objeto que contiene ‘nombre’
echo $row->nombre; // solo hay un registro con el valor de ‘nombre’
Espero haya respondido su pregunta
24 de Abril de 2010
A la pregunta de Alexisontihs: ¿Como realizar una consulta a 2 o mas BD’s del mismo gestor?. Bueno, podria ser creando 2 instancias de la clase DataBase y trabajarlos por separado (en caso que hayan usuarios distintos para cada una de las BD o en cualquier otro caso), ahora solo seria cuestion de instanciar 2 o cuantos quieras.
Pero antes tienen que poner como nuevos parametros a las variables ‘servidor’, ‘usuario’, ‘contraseña’ y ‘
11 de Mayo de 2010
Estimado, muchas gracias por el aporte, me podrias decir que hace el metodo alter()
saludos
3 de Junio de 2010
Buenos Dias, al utilizar esta clase me ha facilitado mucho no tener que crear ni una funcion ni nada que se le pareciera, pero al realizar esta consulta me sobre escribe el campo nombre, de la tabla contacto por el nombre de la tabla producto, ya que solo en la tabla pedidos guardos los id de las otras tablas, hay alguna solucion para esto no teniendo que hacer dos consultas diferentes asi podemos aprovechar al maximo las posibilidades brindadas por MySQL
$sql = “SELECT contacto.nombre, pedidos.po, producto.nombre FROM contacto, pedidos, producto WHERE contacto.id=pedidos.contacto AND producto.id=pedidos.producto ORDER BY pedidos.po DESC LIMIT 1″;
$db->setQuery($sql);
$resultado = $db->loadObject();
echo $resultado->nombre; // me escribe el nombre que aparece en la tabla producto y no el de la tabla contacto
echo $resultado->po;
3 de Junio de 2010
SOLUCIONADO
Solo le tenia que asignas el comando AS con una variable nueva y listo aca les paso el resultado
$sql = “SELECT “;
$sql .= “pedidos.po, pedidos.empaque, pedidos.proceso, pedidos.tamanios, pedidos.observaciones, “;
$sql .= “contacto.nombre AS contacto, contacto.eMail, contacto.sexo, “;
$sql .= “producto.nombre AS producto, producto.ingles, producto.cientifico, “;
$sql .= “congelado.nombre AS congelado “;
$sql .= “FROM “;
$sql .= “contacto, pedidos, producto, empaque, congelado “;
$sql .= “WHERE “;
$sql .= “contacto.id=pedidos.contacto “;
$sql .= “AND producto.id=pedidos.producto “;
$sql .= “AND congelado.id=pedidos.congelado “;
$sql .= “ORDER BY pedidos.po DESC “;
$sql .= “LIMIT 1″;