2011-06-02 12 views
6

Estoy construyendo una clase para manejar Paypal IPNs como parte de un proyecto, y como ya sé que voy a necesitar usarlo de nuevo en al menos dos trabajos más, I quiero asegurarme de estructurarlo de una manera que me permita reutilizarlo sin tener que recodificar la clase; solo quiero tener que manejar los cambios en la lógica comercial.PHP Structure - Interfaces y stdClass vars

La primera parte de la pregunta es re. interfaces. Todavía no entendí su utilidad y cuándo/dónde desplegarlos. Si tengo mi archivo de clase ("class.paypal-ipn.php"), ¿implemento la interfaz en ese archivo?

Esto es lo que estoy trabajando con la medida (la lista de funciones es incompleta, pero es sólo para la ilustración):

CLASS.PAYPAL-IPN-BASE.PHP

interface ipn_interface { 

    //Database Functions 
    // Actual queries should come from a project-specific business logic class 
    // so that this class is reusable. 

    public function getDatabaseConnection(); 
    public function setDatabaseVars($host="localhost",$user="root",$password="",$db="mydb"); 
    public function dbQuery($SQL); 

    //Logging Functions 

    public function writeLog($logMessage); 
    public function dumpLogToDatabase(); 
    public function dumpLogToEmail(); 
    public function dumpLogToFile(); 

    //Business Logic Functions 

    private function getTransaction($transactionID); 

    //Misc Functions 

    public function terminate(); 
} 

class paypal_ipn_base { 

    //nothing to do with business logic here. 

    public function getDatabaseConnection() { 
    } 

    public function setDatabaseVars($host="localhost",$user="root",$password="",$db="mydb") { 
    } 

    public function dbQuery($SQL) { 
    } 

} 

CLASE .paypal-IPN.PHP

final class paypal_ipn extends paypal_ipn_base implements ipn_interface { 

    //business logic specific to each project here 

    private function getTransaction($transactionID) { 

     $SQL = "SELECT stuff FROM table"; 
     $QRY = this->dbQuery($SQL); 

     //turn the specific project related stuff into something generic 

     return $generic_stuff; //to be handled by the base class again. 

    } 

} 

Uso

En este proyecto:

  • Exigir a los archivos de clase, tanto para la base, y la clase de lógica de negocio.
  • Instatiate * paypal_ipn *
  • Escribir código

En otros proyectos:

  • Copiar sobre la base de clase IPN
  • Editar/reescribir la clase de lógica de negocio * paypal_ipn * dentro de las limitaciones de la interfaz.
  • Instantiate * * paypal_ipn
  • Escribir código

Así como se puede ver que estoy literalmente a usarlo para definir grupos de funciones relacionadas y añadir comentarios. Hace que sea más fácil de leer, pero ¿para qué (si es que lo es) otro beneficio para mí? ¿Es para poder juntar el extensor y la clase base y forzar los errores si algo falta?

stdClass Pregunta

La segunda parte de la pregunta está construyendo en el aspecto de la legibilidad. Dentro de la clase hay un número cada vez mayor de variables almacenadas, algunas se establecen en el constructor, otras por otras funciones; se relacionan con cosas como mantener los vars de conexión de la base de datos (y el recurso de conexión en sí), si el código debe ejecutarse en modo de prueba, la configuración para el registro y el registro en sí, y así sucesivamente ...

había empezado a solo construirlos como de costumbre (de nuevo, a continuación incompleta & para la ilustración):

$this->dbConnection = false; 
$this->dbHost = ""; 
$this->dbUser = ""; 
$this->enableLogging = true; 
$this->sendLogByEmail = true; 
$this->sendLogTo = "[email protected]"; 

Pero entonces me imaginé que la lista cada vez mayor podría hacer con un poco de estructura, por lo que lo adaptaron a:

$this->database->connection = false; 
$this->database->host = ""; 
$this->database->user = ""; 
$this->logging->enable = true; 
$this->logging->sendByEmail = true; 
$this->logging->emailTo = "[email protected]"; 

lo que me da una mucho más fácil de leer la lista de variables cuando volcar toda la clase como código que & prueba.

Una vez completo, planeo escribir una extensión específica de proyecto para la clase genérica donde mantendré el SQL real para las consultas - de un proyecto a otro, el procedimiento de IPN de Paypal y la lógica no cambiarán - pero la estructura de la base de datos de cada proyecto lo hará, por lo que una extensión a la clase lo desinfectará todo en un solo formato, por lo que la clase base no tendrá que preocuparse por eso y nunca tendrá que cambiar una vez que esté escrito.

Así que en general solo un control de cordura - antes de ir demasiado lejos en este camino, ¿parece el enfoque correcto?

Respuesta

5

si está utilizando un autocargador de clase, que recomiendo encarecidamente, no desea mantener la interfaz y la clase en el mismo archivo para que la interfaz pueda cargar automáticamente sin necesidad de cargar primero esta clase que la implementa.

Para obtener más información sobre la carga automática: http://php.net/manual/en/language.oop5.autoload.php

otra cosa que puede que desee considerar es que una clase dada pueden impliment varias interfaces y múltiples clases puede implementar la misma interfaz.

Las interfaces se utilizan principalmente para varios patrones de diseño, para aplicar reglas y desacoplar una clase de cualquier clase dependiente. cuando desacopla una clase de sus dependencias, hace que sea mucho más fácil modificar el código en un momento posterior.

por ejemplo, digamos que tiene una clase A que toma en otra clase B como argumento, y esta clase se extiende por todo su código. usted quiere hacer cumplir que solo una clase con un subconjunto específico de métodos puede ser aceptada como este argumento, pero no desea limitar la entrada a una clase concreta y es descendente. en el futuro, puede escribir una clase completamente diferente que no amplíe la clase B, pero sería útil como entrada para la clase A. esta es la razón por la que usaría una interfaz. es un contrato reutilizable entre clases.

Algunos argumentarían que, dado que PHP es un lenguaje dinámico, las interfaces son una complicación innecesaria y, en su lugar, se puede usar la tipificación de pato. Sin embargo, creo que en grandes bases de código multiusuario, las interfaces pueden ahorrar mucho tiempo, permitiéndole saber más acerca de cómo una clase usa otra, sin tener que estudiar el código en profundidad.

si se encuentra con una gran lista de variables que debe pasar entre objetos o funciones, a menudo terminan mereciendo una clase propia, pero cada caso es diferente.

- dependencia ejemplo inyección -

class A implements AInterface { 
    public function foo($some_var) {} 
} 

interface AInterface { 
    public function foo($some_var); 
} 

class B { 
    protected $localProperty; 

    // inject into the constructer. usually used if the object is saved in a property and used throughout the class 
    public function __construct(AInterface $a_object) { 
     $this->localProperty = $a_object; 
    } 

    // inject into a method. usually used if the object is only needed for this particular method 
    public function someMethod(AInterface $a_object) { 
     $a_object->foo('some_var'); 
    } 
} 

ahora se puede ver que se puede escribir otra clase que impliments un método foo (y el AInterface) y el uso que dentro de la clase B también.

como ejemplo del mundo real (se usa a menudo), supongamos que tiene una clase de base de datos con métodos particulares que interactúan con la base de datos (getRecord, deleteRecord). ahora digamos que en un momento posterior encontrará una razón para cambiar la base de datos rdbms. ahora necesita usar declaraciones SQL completamente diferentes para lograr los mismos objetivos, pero ya que usó una interfaz para su tipo de sugerencia, puede simplemente crear una nueva clase que implemente esa interfaz, pero implementa esos mismos métodos de maneras totalmente diferentes ya que interactúa con un rdbms diferente. al crear esta nueva clase, sabrá exactamente qué métodos deben escribirse para esta nueva clase a fin de encajar en los mismos objetos que necesitan usar un objeto de base de datos. si usa una clase de contenedor que usa para crear objetos e insertarlos en otros objetos, no necesitaría cambiar demasiado el código de la aplicación para cambiar las clases de las bases de datos y, por lo tanto, cambiar las bases de datos rdbms. incluso podría usar una clase de fábrica, que podría limitar sus cambios a una línea de código para hacer este tipo de cambio (en teoría).

+0

He editado mi pregunta original un poco para explicar cómo creo que debería estar configurando. Si esto no es correcto, ¿te importaría proporcionar una descripción de un ejemplo del mundo real? No necesito un código específico, simplemente algo con lo que me puedo relacionar :) (Si entiendo correctamente tu respuesta, las interfaces pueden ser la respuesta que he estado buscando al configurar una clase solo para manejar sesiones, y una para manejar completamente conexiones de base de datos: lógicamente, otras clases no son extensiones de éstas, pero sí requieren que estén presentes, es decir, para que un registro se pueda escribir en un DB; ¿así que las interfaces son la respuesta aquí?) – Codecraft

+0

parece que cada una (sesiones, db) merecen sus propias clases, y al menos una interfaz cada una si otras clases dependen de ellas. Entonces, desearía inyectar los objetos derivados de estas clases en los objetos que dependan de ellos. A continuación, puede utilizar la sugerencia de tipo para asegurarse de que solo los objetos que implementan una interfaz específica puedan ser aceptados como argumentos. – dqhendricks

+0

Podría usar un ejemplo de código para ilustrar eso, pero la bombilla en mi cabeza parpadea ... Continuaré pensando en tu respuesta y veré si puedo hacer que funcione de manera permanente, gracias :-) – Codecraft