Foros del Web » Programando para Internet » PHP »

[SOLUCIONADO] PHP OO ¿Cómo utilizar una clase y método con ReflectionClass?

Estas en el tema de ¿Cómo utilizar una clase y método con ReflectionClass? en el foro de PHP en Foros del Web. Esa es mi duda. Estoy investigando una manera de poder separar las variables Get de Post, de manera que desde el index instancia a clases ...
  #1 (permalink)  
Antiguo 26/05/2014, 07:07
Avatar de guardarmicorreo  
Fecha de Ingreso: noviembre-2012
Ubicación: Córdoba
Mensajes: 1.153
Antigüedad: 11 años, 5 meses
Puntos: 84
¿Cómo utilizar una clase y método con ReflectionClass?

Esa es mi duda. Estoy investigando una manera de poder separar las variables Get de Post, de manera que desde el index instancia a clases según Get para presentar contenido y Post para realizar el CRUD.

La idea es poder "llamar a ciegas" a una clase, todo dependiendo de lo que el usuario quiera poder ver según navegue (GET) o pulse (POST).

Entonces a la hora de llamar a una clase con ReflectionMethod utilizando parámetros predefinidos, para por ejemplo, presentar una barra de navegación, pues no me ha dado problema, pero leyendo la doc. de PHP he visto que las características de ReflectionClass me impiden utilizar un método de la clase que obtengo información, ya que ReflectionClass, después de leer toda la doc. he visto que no tiene un invoke o un invokeArgs, que es solo una clase para obtener info de una clase, no es como ReflectionMethod. Y ReflectionMethod no me sirve para lo que estoy haciendo porque una vez que utilizo su __construct no puedo cambiar a otro método manteniendo la misma instancia de la clase, o por lo menos no he visto la manera de poder hacerlo.

¿Qué solución puedo tener al respecto con este problema?

Espero haberme explicado bien. Y sino pongo código de ejemplo, aunque ahora mismo no lo haya visto necesario.
__________________
Ayúdame a hacerlo por mi mismo.
  #2 (permalink)  
Antiguo 26/05/2014, 07:19
Avatar de Italico76  
Fecha de Ingreso: abril-2007
Mensajes: 3.303
Antigüedad: 17 años, 1 mes
Puntos: 292
Respuesta: ¿Cómo utilizar una clase y método con ReflectionClass?

Pues en mi opinion nada tiene que ver con ReflectionClass, para resolver el camino en una aplicacion web estan dos patrones de diseño muy usados por todos los frameworks y muy relacionados:

- Model-View-Controller (MVC)

- Front Controller


... por otro lado para hacer los CRUD, hay distintos patrones que se pueden utilizar en un ORM pero reitero no hay porque forzar el uso de ReflectionClass que por otro lado es MUY costosa.

Adicional.. te puede simplificar la vida usar interfaces e implementar ciertas reglas en los nombres de los metodos (convention over configuration)
__________________
Salu2!
  #3 (permalink)  
Antiguo 26/05/2014, 07:36
Avatar de guardarmicorreo  
Fecha de Ingreso: noviembre-2012
Ubicación: Córdoba
Mensajes: 1.153
Antigüedad: 11 años, 5 meses
Puntos: 84
Respuesta: ¿Cómo utilizar una clase y método con ReflectionClass?

Gracias Italico por tu respuesta, pero estoy experimentando, nada definitivo, no sé ni si estoy en lo correcto con lo que quiero pretender.

De momento este es el código que he confeccionado, para que veas lo que he hecho

Solo muestro el PHP del index.php, que contiene todo lo que necesita un index + spl_autoload_register y el siguiente código para dibujar una barra de navegación
Código PHP:
Ver original
  1. <div id="header">
  2.                 <?php
  3.                 /*
  4.                  * la cabecera
  5.                  */
  6.                 try{
  7.                     $obj=new ReflectionMethod("modules\Head", "paint");
  8.                     echo $obj->invoke(new \modules\Head);
  9.                 } catch (Exception $ex) {
  10.                     echo $ex;
  11.                 }
  12.                 ?>
  13.             </div>

En modules\Head hay lo siguiente
Código PHP:
Ver original
  1. <?php
  2. namespace modules;
  3.  
  4. class Head{
  5.     public function __construct() {}
  6.    
  7.     public function paint(){
  8.         $obj=new \views\Template("navbar");
  9.         return $obj->invoke("navbar");
  10.     }
  11. }

En views\Template hay lo siguiente
Código PHP:
Ver original
  1. <?php
  2. namespace views;
  3.  
  4. class Template{
  5.     public function __construct($envelope) {
  6.        require_once 'html/'.$envelope.'.php';
  7.     }
  8.    
  9.     public function invoke($function, $parameters=null){
  10.         return call_user_func($function, $parameters);
  11.     }
  12. }

Y con eso dibujo una barra de navegación.

Ahora, para presentar al usuario cualquier contenido que solicite y no uno estático, pues necesito llamar a ciegas a una clase, no de manera predefinida, sino dinámica, es decir, que el usuario introduzca variables GET para la URL y con otro try-catch detecto si existe GET, después extraigo todas las variables GET, las introduzco en un array asociativo y los paso como argumento a una clase, en esa clase voy examinando cada valor, si el primer valor corresponde a una clase pues voy pasando argumentos a la subclase de esa primera clase y así consecutivamente hasta llegar a lo que el usuario ha pedido.

Lo mismo haría con POST para el CRUD, con otro try-catch, etc.

Conozco la teoría del MVC, pero no he visto nada práctico que sea fácil de mantener, mucho código suelto es lo que he logrado, eso se puede deber a que soy un programador nefasto o que creo que se pueden hacer las cosas de otra manera, más fácil de hacer y mantener.

No he logrado ver un ejemplo de MVC claro e intuitivo. Sí, podría leer cualquier copia de Codeigniter, Laravel, etc. Pero para alguien como yo que soy tan novato en la programación, pues no me sale a cuentas, sería un martirio y terminaría cansado antes de poder lograr algún avance que me ayude a poder seguir.

Un saludo! :D
__________________
Ayúdame a hacerlo por mi mismo.
  #4 (permalink)  
Antiguo 26/05/2014, 07:38
Avatar de Italico76  
Fecha de Ingreso: abril-2007
Mensajes: 3.303
Antigüedad: 17 años, 1 mes
Puntos: 292
Respuesta: ¿Cómo utilizar una clase y método con ReflectionClass?

No recuerdo si fue @hhs o @dashtrash que te hizo una pregunta en otro post que creo es "clave":

Piensas usar Reflection en "produccion" ?


Lo que sucde es que no es que no puedas hacer algo "serio" con Reflection sino que no es para usarlo todo el tiempo sino diria que exclusivamente para por ejemplo poder hacer una clase como UnitTest de test unitarios o algo como phpDoc quizas..... o quizas como parte de algun framework pero para generar "algo" pero no es para que el flujo de tu programa pase por una clase como ReflectionClass todo el tiempo


EDIT:

Piensas usar call_user_func() ? bueno.. de nuevo... ojo con ese tipo de funciones que caen en la misma categoria que eval() o el uso de $_REQUEST ... son cosas que te pueden traer muchos dolores de cabeza para uso en "produccion" (y lo digo porque hablas tambien de Templates)
__________________
Salu2!
  #5 (permalink)  
Antiguo 26/05/2014, 07:52
Avatar de guardarmicorreo  
Fecha de Ingreso: noviembre-2012
Ubicación: Córdoba
Mensajes: 1.153
Antigüedad: 11 años, 5 meses
Puntos: 84
Respuesta: ¿Cómo utilizar una clase y método con ReflectionClass?

No recuerdo esa pregunta, pero lo importante es ¿qué inconvenientes presenta Reflection para producción? No lo entiendo :S ¿Cuales son los motivos para utilizar esas capcidades de PHP solamente para cuestiones documentativas?

Respecto a cal_user_func ¿lo dices porque corre el peligro de quedar fuera de soporte por deprecated o algo así?

Mil gracias por tus respuestas Italico76, me sirven de ayuda y guía.
__________________
Ayúdame a hacerlo por mi mismo.
  #6 (permalink)  
Antiguo 26/05/2014, 08:03
Avatar de Italico76  
Fecha de Ingreso: abril-2007
Mensajes: 3.303
Antigüedad: 17 años, 1 mes
Puntos: 292
Respuesta: ¿Cómo utilizar una clase y método con ReflectionClass?

- Reflection es costostosa! cuesta mucho tiempo de CPU que es desperdiciado.. realmente tu no necesitas "adivianar" como es una clase para usarla.. la puedes leer, cierto ? no eres un programa...... entonces.. cuando usarla ?

- Reflection es usada para "analizar" programas para propositos de "testing", "documentacion",... etc ... o como decia podria quizas ser parte de algun ORM de un framework para generar / modificar un Modelo en funcion de lo que escribas en un Controlador ... algo como "Active Record" .. pero entiende esto: el flujo del programa no pasa todo el tiempo por alli, solo cuando estas en "Testing" o "Developing"

- call_user_func() podria o no ser depredicada pero si lo es por que ofrece vulenerabilidades, si la usas sin cuidado podrian ejecutar algo que tu no quieres

- Hay muchos ejemplos simples de MVC... se puede hacer uno con pocas lineas de codigo sin clases ni un front-controller
__________________
Salu2!
  #7 (permalink)  
Antiguo 26/05/2014, 08:08
Avatar de guardarmicorreo  
Fecha de Ingreso: noviembre-2012
Ubicación: Córdoba
Mensajes: 1.153
Antigüedad: 11 años, 5 meses
Puntos: 84
Respuesta: ¿Cómo utilizar una clase y método con ReflectionClass?

Ahora entiendo mejor.

Solo me queda pedirte por favor que me muestres un ejemplo práctico y sencillo de MVC con PHP.

Gracias por tu ayuda Italico76.
__________________
Ayúdame a hacerlo por mi mismo.
  #8 (permalink)  
Antiguo 26/05/2014, 09:15
Avatar de Italico76  
Fecha de Ingreso: abril-2007
Mensajes: 3.303
Antigüedad: 17 años, 1 mes
Puntos: 292
Respuesta: ¿Cómo utilizar una clase y método con ReflectionClass?

Bueno... me da pereza escribir un MVC asi sea simple (lo he hecho y no encuentro que lo hice)... ejemplos debe haber varios en StackFlow

Basicamente tu Index.php es donde descompones la URL para estraer las variables, entre las que tendras:

Cita:
index.php?controlador=posts&accion=mostrar&id_post =45
- controlador
- accion
- parametros (id, etc)

Para esto podrias usar parse_url(), entonces sabiendo eso te diriges a un archivo con ese nombre de controlador (.php) y ejecutas la funcion o metodo definido por accion -- digamos accion() -- y le pasas esos parametros

<< hasta ahi tienes separado en FRONT CONTROLLER de los demas CONTROLLERS


Luego... te falta separar aun las VISTAS y los MODELOS, cierto ? una forma es incluir los modelos en los controladores (en cada uno incluyes los modelos a los que necesitas acceder) y luego en vez de escupir HTML en ese controlador lo que haces es por ejemplo incluir un archivo que solo posee HTML y variables de PHP. Supongamos el controlador que te permite en un blog visualizar una entrada (post) en particular (sigamos con el ejemplo)

Vamos a suponer que el Front_controller incluye a los otros controladores (en vez de hacer otra re-direccion), con lo que las variables locales al FRONT son locales para el CONTROLLER incluido:

Código PHP:
Ver original
  1. <?php
  2. // Controller posts_mostrar.php
  3.  
  4. include "models/posts.php";
  5. //include "models/comments.php";
  6. include "views/mostrar_posts.php";
  7.  
  8. // registro de la tabla posts para id = id_post
  9. // funcion get_posts_from_id_post() definida en el modelo incluido
  10.  
  11. $vars['registro'] = get_posts_from_id_post($id);
  12. // lo que quiera en $varsp[]
  13.  
  14.  
  15. // paso las variables locales en un arreglo a la clase que renderiza las vistas
  16. View::render('vista_muestra_entrada',$vars);

Bueno... te faltan las vistas ahora.... y la clase View que la deberias tambien cargar desde cada vista o desde el controlador si va a usar vistas:

Código PHP:
Ver original
  1. <!-- View -->
  2. <?php extract($vars); ?>
  3. <html>
  4. <head>
  5.    <title><?php $nombre_post; ?>
  6. </head>
  7.  
  8. <body>
  9.  
  10.   <h1><?php $nombre_post; ?></h1>
  11.  
  12.   <div class="post_body">
  13.        <?php $desarrollo; ?>
  14.   </div>
  15.  
  16.     <!-- suponiendo tambien usas el modelo Comentarios -->
  17.     <table>
  18.     <?php foreach ($comments as $comment): ?>
  19.        <tr>
  20.           <td>
  21.             <?= $comment['nombre_usuario]; ?>
  22.           </td>
  23.        </tr>
  24.        
  25.         <tr>
  26.           <td>
  27.             <?= $comment['comentario]; ?>
  28.           </td>
  29.        </tr>
  30.   <?php endforeach; ?>
  31.   </table>
  32.  
  33. </body>
  34.  
  35. </html>
__________________
Salu2!

Última edición por Italico76; 26/05/2014 a las 09:44
  #9 (permalink)  
Antiguo 26/05/2014, 15:16
Avatar de guardarmicorreo  
Fecha de Ingreso: noviembre-2012
Ubicación: Córdoba
Mensajes: 1.153
Antigüedad: 11 años, 5 meses
Puntos: 84
Respuesta: ¿Cómo utilizar una clase y método con ReflectionClass?

Gracias Italico76!

Esto me ayuda a reforzar conceptos y código que ya tenía hecho. De todas formas sigo pensando en las maneras de centrarlizar los "cruces" en el camino de la aplicación web.

Porque he visto durante meses que dicho camino es igual en casi todos los MVC, tanto teórico como práctico, incluso yo escribo código como tu me dices.

El problema está en que una aplicación como un blog, algo aparentemente pequeño, puede crear problemas a la hora de añadir funcionalidades. Así que esta estructura, entiendo que viene muy pero que muy bien, para algo sencillo y de una sola tarea. El problema viene cuando el usuario interactua con, por ejemplo, un blog y distintas funcionalidades.

El problema radica en cómo decirle al controller que instancie un modelo u otro y a su vez cómo decirle a un modelo si tiene que terminar en un view o devolver un objeto para otra clase.

No sé si esto sería escalabilidad o cómo se llamaría, pero hasta ahora, este modelo, lo que me ha generado es uno o varios documentos largos donde detectaba cada variable get y post, ahí está el problema, en no terminar con uno o varios archivos para generar el content (parte dinámica de la web) tal que así:

Código PHP:
Ver original
  1. /*
  2.      * si el usuario se ha identificado
  3.      */
  4.     if(isset($_REQUEST['unlogin'])){
  5.             print_unlogin();
  6.             \header('Location:'.$_SERVER['REQUEST_URI']);
  7.     }
  8.     elseif(isset($_SESSION['user'])){
  9.         print_html_unlogin();
  10.     }
  11.    
  12.     /*
  13.      * si pulsa sobre contact
  14.      */
  15.     if(isset($_REQUEST['option']) AND $_REQUEST['option']=='contact'){
  16.         print_contact();
  17.        
  18.         if(isset($_REQUEST['menu']) AND $_REQUEST['menu']=='no_sent'){
  19.             contact_menu_no_sent();
  20.         }
  21.        
  22.         if(isset($_REQUEST['menu']) AND $_REQUEST['menu']=='sent'){
  23.             contact_option_sent();
  24.         }
  25.        
  26.         if(isset($_REQUEST['menu']) AND $_REQUEST['menu']=='bloqued'){
  27.             contact_menu_bloqued();
  28.         }
  29.        
  30.         if(isset($_REQUEST['menu']) AND $_REQUEST['menu']){
  31.             contact_menu_rest();
  32.         }
  33.     }
  34.  
  35.     /*
  36.      * si pulsa sobre timeline
  37.      */
  38.     elseif(isset($_REQUEST['option']) AND $_REQUEST['option']=='timeline'){
  39.         return print_timeline();
  40.     }

etc. etc. etc.

Voy a buscar la manera de reducir todo un documento o varios así para instanciar los modelos y generar las vistas en un front controller y controller. una especie de cuello de botella por donde pase todo el tráfico/camino entre el usuario, el controlador, el modelo y la vista.

Y sobre todo, que sea fácil de entender :D

De nuevo gracias! ;)

Un saludo.
__________________
Ayúdame a hacerlo por mi mismo.
  #10 (permalink)  
Antiguo 26/05/2014, 15:51
Avatar de Italico76  
Fecha de Ingreso: abril-2007
Mensajes: 3.303
Antigüedad: 17 años, 1 mes
Puntos: 292
Respuesta: ¿Cómo utilizar una clase y método con ReflectionClass?

Eso ultimo que escribiste seria como un Front controller si fuera mas "general", fijate que lo que llamas serian los controllers en un MVC .. donde como hablamos haces la otra separacion al incluir modelos (si los necesitas) y vistas (si los necesitas)

Todos esos IF ($_REQUES['algo']) se pueden reducir enormemente a algo como:

Código PHP:
Ver original
  1. if (isset($_GET['controller']))
  2.     include 'controllers/'.$_GET['controller'].'.php';
  3. else
  4.    include 'controllers/_main_.php';

No te aconsejo usar $_REQUEST por seguridad y eso mismo se puede mejorar:

Código PHP:
Ver original
  1. include filter_controller($_GET['controller']));

filter_controller() podria ser el encargado de verificar si ese controlador esta registrado antes de hacer la inclusion y lo haria leyendo un archivo de configuracion y cargandolo como array()

Para esto ultimo puedes usar parse_ini_file()
__________________
Salu2!

Última edición por Italico76; 26/05/2014 a las 16:19
  #11 (permalink)  
Antiguo 27/05/2014, 18:06
Avatar de hhs
hhs
Colaborador
 
Fecha de Ingreso: junio-2013
Ubicación: México
Mensajes: 2.995
Antigüedad: 10 años, 10 meses
Puntos: 379
Respuesta: ¿Cómo utilizar una clase y método con ReflectionClass?

Cita:
Conozco la teoría del MVC, pero no he visto nada práctico que sea fácil de mantener, mucho código suelto es lo que he logrado, eso se puede deber a que soy un programador nefasto o que creo que se pueden hacer las cosas de otra manera, más fácil de hacer y mantener.
El detalle con esto del mvc es que, no basta con conocer como funciona.

Cita:
No he logrado ver un ejemplo de MVC claro e intuitivo. Sí, podría leer cualquier copia de Codeigniter, Laravel, etc. Pero para alguien como yo que soy tan novato en la programación, pues no me sale a cuentas, sería un martirio y terminaría cansado antes de poder lograr algún avance que me ayude a poder seguir.
Me gustaría saber a que te refieres con todo esto. Para entender un poco mas tu situación.

En corto puedes resolver el problema con el patrón Front Controller o con el Page Controller los dos requiere manejar las peticiones para obtener información y decidir a que objetos delegar una petición.
Te dejo un ejemplo de como hacer el fron controller:
Código PHP:
Ver original
  1. class Router {
  2.    
  3.     private static $routes = array();
  4.    
  5.     private function __construct() {}
  6.     private function __clone() {}
  7.    
  8.     public static function route($pattern, $callback) {
  9.         $pattern = '/^' . str_replace('/', '\/', $pattern) . '$/';
  10.         self::$routes[$pattern] = $callback;
  11.     }
  12.    
  13.     public static function execute() {
  14.         $url = $_SERVER['REQUEST_URI'];
  15.         $base = str_replace('\\', '/', dirname($_SERVER['SCRIPT_NAME']));
  16.         if (strpos($url, $base) === 0) {
  17.             $url = substr($url, strlen($base));
  18.         }
  19.         foreach (self::$routes as $pattern => $callback) {
  20.             if (preg_match($pattern, $url, $params)) {
  21.                 array_shift($params);
  22.                 return call_user_func_array($callback, array_values($params));
  23.             }
  24.         }
  25.     }
  26. }
  27.  
  28. //uso
  29. Router::route('blog/categoria/(\d+)', function($category, $id){
  30.   print $category . ':' . $id;
  31. });
  32. Router::execute();

Necesitas usar el modulo rewrite para que obligues a que las peticiones pasan por tu index.php por dar un ejemplo.

Esta es la forma que usan muchos Frameworks como Laravel, Silex, Slim, etc y tambien librerias que solo hacen el mapeo de una url a algo.
Claro esta que en los Frameworks manejan cosas mas complejas pero el principio es valido.
Espero que el ejemplo sea sencillo, ya solo te falta implementar el patrón Command para el Controller y llamarlo dentro de la función anónima o simplemente llamar a tu modelo y pasarle lo necesario a la vista.

P.D. El código no es mio. y no son las únicas opciones.
__________________
Saludos
About me
Laraveles
A class should have only one reason to change.
  #12 (permalink)  
Antiguo 27/05/2014, 20:20
Avatar de guardarmicorreo  
Fecha de Ingreso: noviembre-2012
Ubicación: Córdoba
Mensajes: 1.153
Antigüedad: 11 años, 5 meses
Puntos: 84
Respuesta: ¿Cómo utilizar una clase y método con ReflectionClass?

Revisaré todo lo que me has puesto hss y lo pondré en práctica a ver qué conclusiones saco. Muchas gracias! :D
__________________
Ayúdame a hacerlo por mi mismo.

Etiquetas: clase, variable
Atención: Estás leyendo un tema que no tiene actividad desde hace más de 6 MESES, te recomendamos abrir un Nuevo tema en lugar de responder al actual.
Respuesta




La zona horaria es GMT -6. Ahora son las 18:06.