Ya comenté el tema de usar clases “principales” para un proyecto… y ahora vuelvo con el mismo tema. Muy creativo, sí…
La idea es la de tener un objeto principal (maestro) con un constructor que crea dentro del propio objeto tantos objetos “internos” como hagan falta, pasándole por referencia su propio objeto al constuctor de los “objetos internos”.
Los “objetos internos” extienden a una plantilla de objeto, y esa plantilla contiene un constructor que a su vez “guarda” como referencia el parámetro pasado por el objeto principal.
Sí, es un lío, así que mejor verlo en código:
class AppObjectSkel {
function __construct(&$parent) {
$this->_parent = $parent;
if(is_callable(array($this, 'init'))) $this->init();
}
}
class AppDatabase extends AppObjectSkel {
function init() {
/* Aquí se inicializa la DB */
}
}
class AppCache extends AppObjectSkel {
/* Elemento de cache, no lo inicializamos en este ejemplo */
}
class Application {
function __construct() {
$this->database = new AppDatabase($this);
$this->cache = new AppCache($this);
}
}
De esta manera se puede acceder de un elemento a otro. Por ejemplo, desde AppCache se puede acceder a AppDatabase pasando por Application, simplemente usando $this->_parent->database. Al tratarse de un valor pasado por referencia, se puede acceder desde AppDatabase a AppCache y reflejar cambios en tiempo real.
Pero hay que tener en cuenta un pequeño detalle: los constructores. Debido a que se hereda de una clase maestra (AppObjectSkel), no se puede poner constructor de ningún tipo (ya sea __constructor o una función con el nombre de la clase), ya que PHP ejecutará únicamente el del objeto creado (AppCache, por ejemplo) y no el de AppObjectSkel (y mucho menos va a ejecutar dos constructores). Se puede evitar esto de varias formas: evitando AppObjectSkel en todos los casos y copiando el construct a cada vez, copiando el construct sólo cuando lo necesitamos (por que pisamos el construct de AppObjectSkel) o simplemente usar una función opcional (llamada init), como pongo en el ejemplo, que sólo se ejecuta si existe y se llama desde AppObjectSkel, a modo de constructor (un constructor invoca a otro).
Desde la propia aplicación simplemente hay que crear una nueva instancia del objeto Application ($app = new Application) y acceder a los diferentes objetos a partir del maestro ($app->db, $app->cache).
Esto llega a ser muy útil cuando la aplicación entera está divida en objetos (AppUsers, AppForums, AppProfiles...) y es necesario hacer transacciones entre los objetos. En lugar de crear una instancia para cada objeto cada vez que se necesitan (por ejemplo, instanciar AppCache desde AppUsers cuando hace falta usar memcache), se pueden instanciar una sola vez y acceder en un entorno protegido (Application, que vendría a ser un “contenedor” relativamente protegido de variables pisadas y globales erradas), a todos los objetos o variables que haga falta.
Con esto después se pueden hacer montones de cambios (instanciar una clase poco usada sólo cuando se necesita, hacer una especie de namespace para tener un cache durante la ejecución del programa…). Y es que ahí, la imaginación es el límite.