2011-04-13 8 views
7

yo tengo un par de preguntas sobre las clases PHP pero no se les puede pedir por separado, por lo que aquí voy:Algunos (avanzado) preguntas en torno a las clases PHP

tengo un CMS que estoy construyendo y en el núcleo de ahí están mis clases baseClass, logger, DB y modules. DB y logger son clases estáticas, así que puedo usarlos desde otros objetos. Hay muchas clases de módulos que se cargan en los BaseClass con:

class baseClass { 
    private $_modules; 

    public function __construct() { 
     logger::log("instance created."); 
     $this->_modules = Array() 
    } 

    public function __destruct() { 
     foreach($this->_modules as $name) $this->unloadModule($name); 
     logger::log("instance destroyed."); 
    } 

    public function loadModule($name) { 
     if (class_exists($name)) { 
      if (!isset($this->$name)) { 
       $this->_modules[] = $name; 
       $this->$name = new $name(); 
       logger::log("module '$name' loaded."); 
      } 
      else logger::log("module '$name' already loaded.", 2); 
     } 
     else logger::log("module '$name' does not exist.", 3); 
    } 

    public function unloadModule($name) { 
     if (isset($this->$name)) { 
      unset($this->$name); 
      foreach($this->_modules as $id => $mod_name) { 
       if ($name==$mod_name) { 
        unset($this->_modules[$id]); 
        logger::log("module '$name' unloaded."); 
       } 
      } 
     } 
     else logger::log("module '$name' not loaded.", 2); 
    } 

    public function listModules() { 
     return $this->_modules; 
    } 
} 
$instance = new baseClass(); 
$instance->loadModule('moduleX'); 
$instance->loadModule('moduleY'); 

Pregunta 1: ¿Es mi aplicación loadmodule una buena idea o si tiene una mejor solución. O es posible extender una clase a la inversa, por lo que no tendría que cargar los módulos, en lugar de su definición de clase se carga a sí mismos en los BaseClass como:

class moduleX reverseExtends baseClass { 
    public function f1(); 
    public function f2(); 
} 
class moduleY reverseExtends baseClass { 
    public function f3(); 
    public function f4(); 
} 

$instance = new baseClass(); 
$instance->f1(); 
$instance->f2(); 
$instance->f3(); 
$instance->f4(); 

o al menos:

$instance->moduleX->f1(); 
$instance->moduleX->f2(); 
$instance->moduleY->f3(); 
$instance->moduleY->f4(); 

Pregunta 2: Por ahora estoy usando mi registrador y las clases de DB como clases estáticas (los llamo con logger :: y DB: :) para que sean accesibles desde cualquier contexto y ámbito - ¿es posible instanciar y todavía los utilizo dentro de mi objeto baseClass, pero sin instanciarlos dentro de la baseClass o configurarlos de esta manera dentro de cada clase que voy a usarlo con: métodos diferentes

public function __construct() { 
    global $logger_instance; 
    $this->logger = $logger_instance; 
} 

que he probado que van desde malos como pasando una referencia del objeto original dentro de los BaseClass a feo como el uso de funciones de contenedor. El uso de referencias destruye mi objeto logger cuando baseClass está desarmado y es difícil de acceder a través de módulos - $ this-> base-> logger-> log() - que a su vez requiere una referencia al objeto baseClass ($ this-> base) y mata mi objeto baseClass en unloadModule ... En cuanto a la función de envoltura - Quiero poder tener varias instancias del objeto logger, por lo que pasar un identificador de instancia junto con la función lo hace realmente feo y una solución "falsa".

necesito algo como:

public function someFuncionInsideSomeClass() { 
    $logger->('Log something'); //or $logger('Log something') with __invoke() 
    //$logger here is in the global scope 
} 

Pregunta 3: Quiero un módulo para poder modificar el código de otro. Por ejemplo, tengo un módulo de base de datos cargado, luego cargo un módulo logger y quiero que el módulo logger se integre en el código del módulo de base de datos sin que yo tenga que meterme con su código original. Por supuesto, el registrador tendría que encargarse de la integración en sí (o más bien de mí como codificador). Un simple ejemplo:

class tagCreator { 
    public function createTag($tag,$data) { 
     $tag1 = $tag; 
     $tag2 = '/'.$tag; 
     return "<$tag1>$data<$tag2>"; 
    } 
} 
class styleFunctionality { 
    public function __construct() { 
     //if class is loaded (tagCreator) | load class (tagCreator) 
      //do some magic here to tagCreator 
      //tagCreator -> createTag -> add argument $style 
      //tagCreator -> createTag -> $tag1 += ' style="'.$style.'"' 
     //else issue error tagCreator does not exist 
    } 
} 
$instance = new baseClass(); 
$instance->loadModule('tagCreator'); 

echo $instance->createTag('span','some string'); 
// returns <span>some string</span> 

$instance->loadModule('styleFunctionality'); 

echo $instance->createTag('span','some string','font-weight: bold'); 
// returns <span style="font-weight: bold">some string</span> 

Nota: no me refiero necesariamente la sobrecarga de funciones, que podría querer cambiar sólo un poco de código dentro de un método

Nota 2: Llamar a $ ejemplo-> createTag () no es un error - planeo escribir alguna fantasía función __ llamada() para la clase base para elegir los métodos de sus módulos cargados

lo siento por el tema de largo y gracias por leer hasta aquí, yo incluso appreciat e una respuesta a una sola de mis preguntas :)

+0

Q1 - Puede utilizar la carga automática para cargar sus clases a pedido para que su segundo método de llamada sea posible '$ instancia-> móduloY-> f4();'. P2 - Creo que el método estático sería la manera de ir allí. – JohnP

+0

Pensé en eso, pero a veces podría haber declarado todos los módulos, pero no quisiera que todos los cargaran en mi baseClass. –

+0

Respondí con más detalles. No debería cargar en su clase base – JohnP

Respuesta

3

Para DB y Logger, consideraría utilizar un patrón de Singleton.

<?php 
class Singleton { 
    private static $instance; 

    private function __construct() { 
     // no-op 
    } 
    /** 
    * Create the instance or return the instance if it has already been created. 
    * 
    * @return object 
    */ 

    static public function get_instance() { 
     if (!isset(self::$instance)) { 
      $c = __CLASS__; 
      self::$instance = new $c; 
     } 
     return self::$instance; 
    } 
} 

?> 

En general, es posible que desee consultar los marcos de PHP que requieren PHP5 como Kohana. Y, en lo que respecta a patrones y PHP, es posible que desee consultar "Objetos PHP, patrones y práctica".

+0

Solo recomendaría usar Singletone para el registrador ya que es su función de depuración y debería hacerlo más tarde. estar deshabilitado en la producción ... Singletone for Database tiene un mal sabor ya que siempre tendrá problemas con la prueba de su código más adelante (si lo desea) – chozilla

1

Q1 - Utilizaría un autoloader function para cargar las clases.Puede analizar el nombre de clase para averiguar cuál es la ubicación y el tipo de la clase que está intentando cargar (por ejemplo, controlador, módulo, complemento, etc.).

Junto con __get() (en su clase base) podrá llamar a sus módulos como $instance->moduleX->f1(); si lo desea.

Q2 - Utilizo las clases estáticas para este tipo de actividades también. Además de tener una variable disponible a nivel mundial, con riesgos de conflicto con tu código en otras áreas, no hay mucho más que puedas hacer.

Q3 - Hay un patrón para algo similar a lo que intentas lograr, pero por mi vida parece que no puedo recordarlo en este momento. Pero cómo va esto, necesitarás registrar tu clase de modificador con tu clase principal. Al analizar cómo ha estructurado su aplicación, puede obtenerla mirando el conjunto de módulos de la clase base o pasando la clase modificadora a su clase principal (tagCreator).

Independientemente de cómo lo decida, debe modificar su método createTag() para buscar clases de modificadores cargados (styleFunctionality) antes de devolver la salida. Sus clases de modificador necesitarán, por supuesto, algún tipo de interfaz estándar para que llame su clase principal.

Una palabra de advertencia, mirando cómo está cargando sus módulos en la misma instancia. Puede tener conflictos si dos clases tienen el mismo método definido. Te recomiendo que accedas a ellos por separado, como $this->ModuleA->aMethod().

+0

Para Q3, ¿cree que está buscando el patrón de fábrica? – preinheimer

+0

@preinheimer nope, no es el patrón de fábrica. Eso es bueno para crear los objetos. Veamos lo que google muestra – JohnP

+0

Ohh muy confundido. ¿Observador? http://en.wikipedia.org/wiki/Observer_pattern – preinheimer

Cuestiones relacionadas