Retroceder   Foros del Web > Programación para sitios web > PHP > PHP orientado a objetos

Respuesta
 
Herramientas Desplegado
Antiguo 21-mar-2005, 08:46   #1 (permalink)
Moderador
Cluster llegará a ser famoso muy prontoCluster llegará a ser famoso muy pronto
 
Fecha de Ingreso: noviembre-2002
Ubicación: Santiago - Chile
Mensajes: 34.437
Extender objetos

Hola ..

(introducción)
Estoy usando la classe "FPDF" (www.fpdf.org) que genera PDF's dinámicos desde PHP. Bien, dicha classe tiene como ejemplos bastantes "classes" que extienden a la classe padre para aportar nuevas funcionalidades.

Hasta aquí todo OK, .. el detalle está que cada extensión funciona por sí sola pero hay funcionalidades de várias extensiones (que extenden a la classe padre) que me gustaría usar.

Actualmente .. lo único que hago es tomar todos esos métodos y demás lógica del las classes "extensoras" (no sé como llamarlo) y las uno (cut-and-poaste) sobre una classe "extended". Supongo que esto si bien funciona . .no será lo "políticamente correcto" .. así que quería saber si UDs. conocen la técnica para trabajar este tipo de problemas .. Supongo que algún array como "contenedor" y temas similares .. pero mi conocimiento de OOP es bajo .. sólo soy "usuario" de OOP con este requerimiento. (para ejemplos .. please con "peritas y manzanas" xDD).

En resumen dispongo de N classes que extienden a la padre tipo:

Código PHP:
class PDF extends FPDF {

var 
$DisplayPreferences='';

function 
DisplayPreferences($preferences) {
    
$this->DisplayPreferences.=$preferences;
}

function 
_putcatalog()
{
    
parent::_putcatalog();
    if(
is_int(strpos($this->DisplayPreferences,'FullScreen')))
        
$this->_out('/PageMode /FullScreen');
    if(
$this->DisplayPreferences) {
        
$this->_out('/ViewerPreferences<<');
        if(
is_int(strpos($this->DisplayPreferences,'HideMenubar')))
            
$this->_out('/HideMenubar true');
        if(
is_int(strpos($this->DisplayPreferences,'HideToolbar')))
            
$this->_out('/HideToolbar true');
        if(
is_int(strpos($this->DisplayPreferences,'HideWindowUI')))
            
$this->_out('/HideWindowUI true');
        if(
is_int(strpos($this->DisplayPreferences,'DisplayDocTitle')))
            
$this->_out('/DisplayDocTitle true');
        if(
is_int(strpos($this->DisplayPreferences,'CenterWindow')))
            
$this->_out('/CenterWindow true');
        if(
is_int(strpos($this->DisplayPreferences,'FitWindow')))
            
$this->_out('/FitWindow true');
        
$this->_out('>>');
    }
}

y otra más por ejemplo ...
Código PHP:
class PDF_Javascript extends FPDF {

    var 
$javascript;
    var 
$n_js;

    function 
IncludeJS($script) {
        
$this->javascript=$script;
    }

    function 
_putjavascript() {
        
$this->_newobj();
        
$this->n_js=$this->n;
        
$this->_out('<<');
        
$this->_out('/Names [(EmbeddedJS) '.($this->n+1).' 0 R ]');
        
$this->_out('>>');
        
$this->_out('endobj');
        
$this->_newobj();
        
$this->_out('<<');
        
$this->_out('/S /JavaScript');
        
$this->_out('/JS '.$this->_textstring($this->javascript));
        
$this->_out('>>');
        
$this->_out('endobj');
    }

    function 
_putresources() {
        
parent::_putresources();
        if (!empty(
$this->javascript)) {
            
$this->_putjavascript();
        }
    }

    function 
_putcatalog() {
        
parent::_putcatalog();
        if (isset(
$this->javascript)) {
            
$this->_out('/Names <</JavaScript '.($this->n_js).' 0 R>>');
        }
    }

Instancio y uso el objeto (ahora uno sólo) tipo:
Código PHP:
$pdf=new PDF();
$pdf->SetDisplayMode('fullpage');
$pdf->DisplayPreferences('HideMenubar,HideToolbar,HideWindowUI');
$pdf->AddPage();
$pdf->SetFont('Arial','',16);
$pdf->Write(6,'Only the document should appear, no interface element.');
$pdf->Output(); 
Pero, .. claro .. si intento hacer eso con los dos . .pues alega PHP sobre duplicidad de classes (lógico) ..

He visto que algunas veces se extienden en "cadena" (el padre al hijo .. del hijo al nieto ... ) .. Podría servir .. pero realmente no son "padre ->hijo" sino todas son al padre (nuevos métodos). (tal vez aquí esté confundido .. esa es la impresión que me dá sin haber leido mucha teoría al respecto sobre modelos y temas afines).

Un salduo,
Cluster está desconectado   Responder Citando
Antiguo 22-mar-2005, 11:42   #2 (permalink)
sism82 ha deshabilitado el karma
 
Avatar de sism82
 
Fecha de Ingreso: octubre-2003
Ubicación: Guadalajara
Mensajes: 865
Enviar un mensaje por MSN a sism82 Enviar un mensaje por Yahoo  a sism82
que tal.
Si es que entiendo bien tu cuestinamiento, lo que necesitas es crear una clase totalmente nueva que manipule tantas extensiones como desees. Es decir, esta nueva clase se especializa en manipular extensiones de la clase FPDF. Podriamos llamarla 'FpdfExtensionHandler' y no hereda de ninguna otra clase, sino instancia objetos que heredan de Fpdf, de tal forma que podrías tener algo asi:

Código PHP:
final class FpdfExtensionsHandler
{
    const 
HANDLERS_DIRECTORY 'path/al/directorio/de/las/clases_extensiones/';
    private 
$extensions      = array();
    public  
$extension       null;
    
    public function 
__construct()
    {
        return 
true;
    }
    
    
/**
     * @return Bool
     * @param String $ExtensionName
     */
    
public function LoadExtension($ExtensionName)
    {
        
$extension_path self::HANDLERS_DIRECTORY.$ExtensionName
        
if ( file_exists($extension_path) && !class_exists($ExtensionName) )
        {
            include_once(
$extension_path);
            
$this->extensions[$ExtensionName] = new $ExtensionName();
        }
        return 
true;
    }
    
    
/**
     * @return Bool
     * @param String $ExtensionName
     */
    
public function SetExtension($ExtensionName)
    {
        if ( 
array_key_exists($ExtensionName,$this->extensions) )
        {
            
$this->extension =& $this->extensions[$ExtensionName];
        }
    }

de esta forma tu puedes cargar las extensiones que desees dentro del mismo objeto, simplemente usas el método LoadExtension para cargarlo, y luego SetExtension para usar la extensión que desees, la variable $this->extension siempre apunta a la extensión seleccionada.

Espero haber entendido correctamente tu cuestionamiento. Este proceso te permite seguir cargando tantas extensiones como desees. Obviamente hacen falta métodos para comprobar la existencia de las clases, etc etc.

saludos
__________________
Se debe llamar GNU/Linux, no solamente Linux, mas info en: http://www.gnu.org/gnu/gnu-linux-faq.es.html
sism82 está desconectado   Responder Citando
Antiguo 22-mar-2005, 14:29   #3 (permalink)
Moderador
Cluster llegará a ser famoso muy prontoCluster llegará a ser famoso muy pronto
 
Fecha de Ingreso: noviembre-2002
Ubicación: Santiago - Chile
Mensajes: 34.437
Gracias sism82,

Mas o menos entendí tu planteamiento. Sobre la implementación (el prototipo) que propones, veo que usas el modelo de datos de OOP De PHP 5 .. actualmente uso PHP4 .. así que las declaraciones de los métodos públicos y privados no lo voy a poder hacer así .. ¿Tendría que cambiar alguna cosa más para adaptar el ejemplo a PHP4?

Un saludo,
Cluster está desconectado   Responder Citando
Antiguo 23-mar-2005, 07:41   #4 (permalink)
sism82 ha deshabilitado el karma
 
Avatar de sism82
 
Fecha de Ingreso: octubre-2003
Ubicación: Guadalajara
Mensajes: 865
Enviar un mensaje por MSN a sism82 Enviar un mensaje por Yahoo  a sism82
fuera de las palabras reservadas como final, private, public etc. Creo que php4 tampoco acepta declaraciones de constantes de clase (const), entonces la constante HANDLERS_DIRECTORY puedes usarla como variable interna, o bien, sacarla de la clase, yo creo que es preferible lo primero. Creo que con eso basta para adaptarlo a php4.

Suerte
__________________
Se debe llamar GNU/Linux, no solamente Linux, mas info en: http://www.gnu.org/gnu/gnu-linux-faq.es.html
sism82 está desconectado   Responder Citando
Antiguo 23-mar-2005, 09:18   #5 (permalink)
Moderador
Cluster llegará a ser famoso muy prontoCluster llegará a ser famoso muy pronto
 
Fecha de Ingreso: noviembre-2002
Ubicación: Santiago - Chile
Mensajes: 34.437
Gracias .. probaré a ver si me resulta.

Un saludo,
Cluster está desconectado   Responder Citando
Antiguo 26-mar-2005, 17:33   #6 (permalink)
Moderador PHP
jpinedo ha deshabilitado el karma
 
Avatar de jpinedo
 
Fecha de Ingreso: septiembre-2003
Ubicación: Piura
Mensajes: 2.740
Cita:
Iniciado por Cluster
Pero, .. claro .. si intento hacer eso con los dos . .pues alega PHP sobre duplicidad de classes (lógico)
Cluster... podrías explicar un poco más este asunto porque no acabo de entender el problema??
Saludos
jpinedo está desconectado   Responder Citando
Antiguo 28-mar-2005, 05:06   #7 (permalink)
Moderador
Cluster llegará a ser famoso muy prontoCluster llegará a ser famoso muy pronto
 
Fecha de Ingreso: noviembre-2002
Ubicación: Santiago - Chile
Mensajes: 34.437
Cita:
Iniciado por jpinedo
Cluster... podrías explicar un poco más este asunto porque no acabo de entender el problema??
Saludos
OK, voy a tratar de gráficar mejor el problema:

Como comentaba .. uso una classe "padre" (fpdf) .. dicha classe, por parte de usuarios han creado funcionalidades nuevas para ella. Las pueden ver en:
http://www.fpdf.org/es/script/index.php

Si se fijan .. todas son un "extended" (o hacen mejor dicho) a la classe "fpdf". Por si sólas funcionan de forma independiente y bien. Ahora, el detalle es ¿que sucede si dese usar várias de estas classes "extended" simultáneamente? (dicho de otra forma o mejor: usar algunos métodos de alguna y otra classe de las que extienden a fpdf).

Por eso .. necesito algún método o técnica para poder "llamar" a cada uno de estos "extenden" (classe) a modo de "pre-carga" y bajo una misma instancia tipo:

$pdf=new PDF();

Poder llamar a un método (supongo que nuevo) tipo:

$pdf->CargaExtended(nose.pdf ó nombre_Classe);

Y a partir de ahí .. poder usar esos métodos que están en la classe "nombre_Classe" que cargue .. pero con la peculiaridad de que no sea uno a uno sino poder "cargar" várias classes "extended" a la vez:

$pdf->CargaExtended(nose.pdf ó nombre_Classe);
$pdf->CargaExtended(nose.pdf ó nombre_Classe);
$pdf->CargaExtended(nose.pdf ó nombre_Classe);
(o como array ... o separado por parámetros las llamadas a más classes extended)

Más o menos es la idea de sism82, pero adaptado para el modelo de datos de POO de PHP4 a ser posible.

Un saludo,
Cluster está desconectado   Responder Citando
Antiguo 28-mar-2005, 12:12   #8 (permalink)
MartinTandil ha deshabilitado el karma
 
Fecha de Ingreso: marzo-2005
Mensajes: 163
Enviar un mensaje por MSN a MartinTandil
A veces dicen que es mejor no meterse, ya que se puede generar mas confusion que otra cosa. Si no entiendo mal tu problema es que tenes en la jerarquia de clases, como padre a fpdf y varias clases hijas que proveen diferentes servicios. No te alcanzaria con hacer un casting de un objeto padre a uno de los hijos y usar los servicios del hijo? Es decir, :
Código PHP:
$pdf=new PDF();
$algo = (extenedClase)$pdf;
//este tipo de casting no funciona, pero es para entender la idea
$algo->servicio(); 
Este codigo sacado de http://ar2.php.net/oop habla de castings.

Código PHP:
<?php 
class foo 
   function 
foo($name="foo") { 
       
$this->name=$name
   } 


class 
bar extends foo 
   function 
boom() { 
       echo 
"BOOOM!"
   } 


$f = new foo(); 
$temp explode(":",serialize($f)); 
$temp[2] = "\"bar\""
$b unserialize(implode(":",$temp)); 

$b->boom(); 

?>
Si entendi cualquier cosa les pido disculpas...
Suerte :)

Última edición por MartinTandil; 28-mar-2005 a las 12:13.
MartinTandil está desconectado   Responder Citando
Antiguo 28-mar-2005, 14:53   #9 (permalink)
Moderador
Cluster llegará a ser famoso muy prontoCluster llegará a ser famoso muy pronto
 
Fecha de Ingreso: noviembre-2002
Ubicación: Santiago - Chile
Mensajes: 34.437
Si, MartinTandil ... hasta ahí lo tengo claro .. pero el detalle es que quiero usar várias de esas classes "bar" de tu ejemplo con sus própios métos que estas implemente y que en su base extienden al padre pero "uno por uno" pero quiero usarlas simultánemente, disponer de todos los métodos de unas y de otras para usarlos ..

Un saludo,
Cluster está desconectado   Responder Citando
Antiguo 28-mar-2005, 16:40   #10 (permalink)
Moderador PHP
jpinedo ha deshabilitado el karma
 
Avatar de jpinedo
 
Fecha de Ingreso: septiembre-2003
Ubicación: Piura
Mensajes: 2.740
Discúlpame pero creo que recién voy entendiendo el problema:
Lo que quieres es manejar una sola instancia:
$pdf = new ExtensionesDeFpdf();

Porque lo que quieres es tener en esa variable/objeto ($pdf) la funcionalidad de varias de las hijas de fpdf.
De esa manera al final sólo hacer un :
$pdf->output();

Lo que estás haciendo ahora es definir (con copiar-pegar) todos los métodos dentro de una sola clase y por eso funciona... pero quieres algo "mejor hecho" o "más ortodoxo".

¿Estoy en lo cierto?
jpinedo está desconectado   Responder Citando
Antiguo 28-mar-2005, 19:12   #11 (permalink)
Moderador PHP
jpinedo ha deshabilitado el karma
 
Avatar de jpinedo
 
Fecha de Ingreso: septiembre-2003
Ubicación: Piura
Mensajes: 2.740
Lo que yo creo es que esas extensiones no han sido escritas para trabajar juntas.
La verdad no tengo idea de cómo solucionar tu problema... pero al parecer el tema tiene que ver directamente con la herencia múltiple (no soportada por PHP, y que se supone que podría suplirse de manera efectiva con la composición).
Digo esto porque lo que necesitas es una clase que herede de todas esas extensiones .... o sea que implemente todos sus atributos y métodos.
Por eso creoq tendrías que buscar alternativas a la herencia múltiple, pero que te den un mayor control porque hay varios métodos del padre que son redefinidos por las hijas y hay que saber cuál de todos querría utilizarse.

Con la solución de sism82 lo que estarías haciendo es tener un montón de instancias (cada una de una Clase hija) y las acciones tendrán efecto en cada una de esas instancias por separado.
Entonces al hacer algo como:
$pdf->output();
¿Qué pasaría?... no creo que funcione como se espera. Pero tal vez sism82 puede ponernos un ejemplo de cómo se utilizaría su clase en este caso particular.

Saludos
jpinedo está desconectado   Responder Citando
Antiguo 29-mar-2005, 06:39   #12 (permalink)
Moderador
Cluster llegará a ser famoso muy prontoCluster llegará a ser famoso muy pronto
 
Fecha de Ingreso: noviembre-2002
Ubicación: Santiago - Chile
Mensajes: 34.437
Gracias Jpinedo .. Realmente no me he metido con OOP .. sólo a nivel "usuario" de classes.

El problema como comenté lo solvento "pegando" físicamente esos métodos que uso de uno y de otra classe "extended" que dispongo sobre una sóla .. así todo funciona bien.. Pero la idea es la de crear un sistema más dinámico a modo de sistema "plug-in" para una classe "padre" .. Pero si PHP hasta la fecha (o peor todavía para PHP 4 que es lo que realmente necesito usarlo) no lo soporta .. mm bueno.. "es lo que hay" no importa, nos esperaremos a que PHP soporte dichas funcionalidades (o yo me pueda cambiar a PHP 5 si es que este las soporta).

Un saludo,
Cluster está desconectado   Responder Citando
Antiguo 29-mar-2005, 07:58   #13 (permalink)
sism82 ha deshabilitado el karma
 
Avatar de sism82
 
Fecha de Ingreso: octubre-2003
Ubicación: Guadalajara
Mensajes: 865
Enviar un mensaje por MSN a sism82 Enviar un mensaje por Yahoo  a sism82
Que tal. Mmm es posible que no este viendo el problema. O bien, no explique bien el funcionamiento del código que puse anteriormente. No recuerdo del todo bien lo que puse pero la idea es sencilla. Los métodos a implementar, ya sea con php4 o php5 (da igual) son:

PdfExtensionHandler::LoadExtenstion($StringExtensi onName);

este método instanciaria dinamicamente las extensiones que desees utilizar, digamos que durante el proceso de una página vas a utilizar 3 extensiones, entonces llamas consecutivamente 3 veces:

Código PHP:
$pdf_extension_handler->LoadExtension('AlgunaExtension');
$pdf_extension_handler->LoadExtension('SegundaExtension');
$pdf_extension_handler->LoadExtension('TerceraExtension'); 
con eso, suponiendo que todo sale bien, se crean internamente las instancias de cada uno de las extensiones. Ahora, para utilizarlas, defines cual quieres usar con:

PdfExtensionHandler::SetExtension($StringExtension Name)
Que lo que hace es posicionar en la variable PdfExtensionHandler::$Extension, una referencia a la instancia de la extensión seleccionada.

Código PHP:
$pdf_extension_handler->SetExtension('SegundaExtension');
$pdf_extension_handler->extension->AlgunMetodoDeSegundaExtension();
$pdf_extension_handler->extension->OtroMetodoDeSegundaExtension();
$pdf_extension_handler->extension->TercerMetodoDeSegundaExtension(); 
En php 5 incluso pudieras ir un paso mas y omitir la variable interna $extension, e implementar el método mágico _call($MethodName), que basicamente es el punto donde todas las llamdas a un método no implementado serán dirigidas, entonces dentro de ese método mágico _call, tu harias la llamada a $this->extension->$MethodName($args); y de esa forma sería llamado el método del objeto al que este apuntando la referencia de $extension

este es un ejemplo de como uso esa función para desplegar un error de 'feature not supported'

Código PHP:
    /**
     * This function will work only in PHP5, catch all the undefined method calls.
     * Previous versions drop a fatal error when an undefined method is called
     * @date Jan/15/2005
     * @return bool
     * @param String CalledMethodName
     * @param Array $Parameters
     * @access magic
     */
    
function __call($CalledMethodName$Parameters
    {
        
$error_arguments = array();
        
$error_arguments['method'] = $CalledMethodName;
        return 
$this->HandleError(PDB_ERROR_FEATURE_NOT_SUPPORTED$error_arguments);
    } 
Si no deseas o no puedes usar php5, pues entonces tendrás que hacer las llamadas a los métodos directamente usando la referencia $extension.
Que inconveniente existe con esta implementación?
La herencia multiple dudo que alguna vez vaya a ser implementada en php, en general he leído que no es recomendada, hace mas confusas las cosas, por ello Java se olvidó de usar la herencia multiple y a cambio hizo lo mas cercano que pudo con las interfaces.

espero haber sido mas explicito esta vez, saludos.

en este caso $Parameters no lo utilizo, pero es parte de la definición del método magico _call
__________________
Se debe llamar GNU/Linux, no solamente Linux, mas info en: http://www.gnu.org/gnu/gnu-linux-faq.es.html
sism82 está desconectado   Responder Citando
Antiguo 29-mar-2005, 08:48   #14 (permalink)
Moderador
Cluster llegará a ser famoso muy prontoCluster llegará a ser famoso muy pronto
 
Fecha de Ingreso: noviembre-2002
Ubicación: Santiago - Chile
Mensajes: 34.437
Entonces sim82 .. bajo el concepto que explicas, el uso alternativo de esas extensiones pre-cargadas ¿sería tipo?:

Código PHP:
$pdf_extension_handler->SetExtension('SegundaExtension'); 
$pdf_extension_handler->extension->AlgunMetodoDeSegundaExtension(); 
$pdf_extension_handler->extension->OtroMetodoDeSegundaExtension(); 
$pdf_extension_handler->extension->TercerMetodoDeSegundaExtension(); 

$pdf_extension_handler->SetExtension('OtraExtension'); 
$pdf_extension_handler->extension->AlgunMetodoDeOtraExtension(); 
$pdf_extension_handler->extension->OtroMetodoDeOtraExtension(); 
$pdf_extension_handler->extension->TercerMetodoDeOtraExtension(); 
Y para llamar a un método de la classe "padre"?

sería?:
Código PHP:
$pdf_extension_handler->metodo_classe_padre(); 
Un saludo,

Última edición por Cluster; 29-mar-2005 a las 08:51.
Cluster está desconectado   Responder Citando
Antiguo 29-mar-2005, 13:06   #15 (permalink)
sism82 ha deshabilitado el karma
 
Avatar de sism82
 
Fecha de Ingreso: octubre-2003
Ubicación: Guadalajara
Mensajes: 865
Enviar un mensaje por MSN a sism82 Enviar un mensaje por Yahoo  a sism82
Correcto. Ahora, para llamar a un método de la clase padre, no podrías hacer lo que indicas, recuerda que la clase que creamos no hereda de Fpdf, no hereda de ninguna, sino que manipula instancias de las clases hijas de Fpdf. Como lo hacemos? se me ocurre sencillamente que puedes mandarlo llamar desde cualquier clase hija, es decir, seria lo mismo:

Código PHP:
$pdf_extension_handler->SetExtension('SegundaExtension');
$pdf_extension_handler->extension->MetodoClasePadre(); 

//lo anterior es igual que

$pdf_extension_handler->SetExtension('TerceraExtension');
$pdf_extension_handler->extension->MetodoClasePadre(); 
por que tanto segunda como tercera extensión heredan del mismo padre, por lo tanto los métodos de la clase padre son compartidos por todas las clases hijas, es decir, por todas las extensiones. Por ello no importaría cual extensión este "seteada", cualquiera tiene acceso a los métodos del padre.
Si no te gusta eso, puedes hacer una referencia a la clase padre en una nueva variable interna llamada $padre y utilizarla como

Código PHP:
$pdf_extension_handler->padre->PrimerMetodoPadre()
$pdf_extension_handler->padre->SegundoMetodoPadre(); 
O tal vez no entendí tu pregunta, si es asi, a ver si me la puedes repetir :p
__________________
Se debe llamar GNU/Linux, no solamente Linux, mas info en: http://www.gnu.org/gnu/gnu-linux-faq.es.html
sism82 está desconectado   Responder Citando
Antiguo 29-mar-2005, 18:32   #16 (permalink)
Moderador PHP
jpinedo ha deshabilitado el karma
 
Avatar de jpinedo
 
Fecha de Ingreso: septiembre-2003
Ubicación: Piura
Mensajes: 2.740
El problema sería que hay hijas que redefinen métodos del padre... por lo que supongo que podrías tratar al padre como una extensión más. De esa manera te aseguras de utilizar los métodos originales del padre. O sea:
Código PHP: