En el software orientado a objetos, la información se representa como clases y objetos. En las bases de datos relacionales, como tablas y sus restricciones. Por tanto, para almacenar la información tratada en un programa orientado a objetos en una base de datos relacional es necesaria una traducción entre ambas formas.
Una aproximación ampliamente usada es el mapeo objeto-relacional (ORM). Tanto en la forma de Table gateway como de Table-row gateway, se hace una correspondencia entre los siguientes elementos:
Programa OO | BD relacional |
---|---|
Clase | Tabla |
Propiedad | Campo |
Objeto | Fila |
Identificador | Clave primaria |
Puntero a otro objeto | Clave foránea |
Esta correspondencia es muy "natural" ya que, en realidad el modelo orientado a objetos y el modelo relacional no son tan diferentes. Veámoslo: en los programas las instancias de un objeto son accedidas a través de un puntero a su posición de memoria. Por ejemplo:
$a = new A;
$b = $a;
En la ejecución del código anterior se realizan las siguientes acciones:
Conceptualmente, podemos decir que el registro en memoria es propiamente el estado del objeto y su posición, indicada en $a, un identificador único del mismo. Y recordemos que los objetos anidados (es decir, las propiedades de $a que sean, a su vez, otros objetos) se almacenarán en el registro como punteros a otros registros.
Esta forma de almacenar información a bajo nivel —manejada comúnmente en el lenguaje C— se asemeja al modelo de las tablas y las relaciones de las bases de datos relacionales: cada registro es una fila, cada puntero una referencia foreign key. Las posiciones en memoria, es decir, los "identificadores únicos" de los objetos podríamos tratarlos como primary keys.
Pero si es tan sencilla la traducción objeto-relacional, ¿por qué la industria sigue usando DAO o sentencias agnósticas? Cuatro principales motivos:
class A {
public $foo;
}
$a = new A;
$a->bar = true;
Además, el tipo de cualquier propiedad, declarada o dinámica, puede ser modificado en tiempo de ejecución:
class A {
//Dándole un valor por defecto a la propiedad, declaramos su tipo
public $foo = "valor";
}
$a = new A;
$a->foo = 3.14;
Estos problemas nos llevan a pensar que, además de la traducción objeto-relacional, PHP presenta un problema añadido de representación de la información, y es que las estructuras de orientación a objetos no son suficientes para definir la información de forma tan concreta como necesitan las bases de datos relacionales. Ante este problema, las soluciones existentes son las siguientes:
class Libro extends AppModel {
/* Las propiedades de Libro son obtenidas automáticamente
* a partir del esquema de BD (tabla "libros")
*/
var $belongsTo = array("Autor");
}
/* Devuelve todos los objetos Libro de la base de datos como array
* multidimensional (¡no como array de objetos!)
*/
$libros = $this->Libro->findAll();
foreach ($libros as $libro) {
echo $libro['titulo'] . " (" . $libro['isbn'] . ")\n";
}
Libro:
columns:
titulo: string(200)
isbn: integer(10)
autor_id: integer(10)
relations:
Autor:
local: autor_id
foreign: id
foreignAlias: Autor
Autor:
columns:
id: integer
nombre: string(100)
class Libro extends TypeSafe {
/** @var string */
public $titulo;
/**
* @var int
* @length 10
* @required
*/
public $isbn;
/** @var Autor */
public $autor;
}
Cabe resaltar que este método de tipado fuerte en PHP no solo es útil en el almacenamiento de datos, sino en la gestión de la información en general, y será desarrollado en el futuro para permitir validación de datos en los modelos de una aplicación MVC.