Foros del Web » Programando para Internet » PHP »

[SOLUCIONADO] PHP OO ¿Pasar un identificador de una funcion a variable e incluirla en una sentencia?

Estas en el tema de ¿Pasar un identificador de una funcion a variable e incluirla en una sentencia? en el foro de PHP en Foros del Web. Tengo la siguiente gran duda que me ha surgido y no logro resolver. Si en un directorio B tengo un documento b.php con el siguiente ...
  #1 (permalink)  
Antiguo 22/02/2015, 09:23
Avatar de guardarmicorreo  
Fecha de Ingreso: noviembre-2012
Ubicación: Córdoba
Mensajes: 1.153
Antigüedad: 12 años
Puntos: 84
¿Pasar un identificador de una funcion a variable e incluirla en una sentencia?

Tengo la siguiente gran duda que me ha surgido y no logro resolver.

Si en un directorio B tengo un documento b.php con el siguiente código

Código PHP:
Ver original
  1. <?php
  2. namespace B;
  3.  
  4. function b(){
  5.     ?>
  6.     <p>hola mundo</p>
  7.     <?php
  8. }

En otro directorio A tengo un documento a.php con el siguiente código

Código PHP:
Ver original
  1. <?php
  2. namespace A
  3.  
  4. class A{
  5.     public function invoke($func){
  6.         //esto devuelve error de sintaxis
  7.         return \B\$func();
  8.     }
  9. }
  10. ?>

Entonces, cómo lo anterior da error de sintaxis, probé con esto otro

Código PHP:
Ver original
  1. <?php
  2. namespace A
  3. class A{
  4.     public function invoke($func){
  5.         //esto devuelve un string, era evidente, pero por probar...
  6.         return "\B\${func}()";
  7.     }
  8. }
  9. ?>

Entonces decidí incluir el archivo

Código PHP:
Ver original
  1. namespace A
  2.  
  3. //incluye un documento
  4. function load($func){
  5.     include "./html/${func}.php";
  6. }
  7.  
  8. class A{
  9.     public function invoke($func){
  10.         load($func);
  11.         return ${func}();
  12.     }
  13. }

En este punto, no reconoce la función b(), sí incluye el archivo, porque no devuelve error, notice, etc. pero dice que esa función no ha sido econtrada; entonces deduje que era porque el namespace en dónde está definida la función es distinto: se produce un cambio de namespace.

Así que quité el namespace en donde está escrita la funcion b() y efectivamente sí funcionó el código.

Siempre teniendo en cuenta que llamo a la clase A desde un documento en un directorio de jerarquía superior con spl_autoload_register();

Y claro, la duda es

¿no hay una manera de poder llamar a la función (en un ambiente dónde la llamada debe ser ciega/dinámica para poder utilizar cualquier función dentro del directorio B) utilizando algo cómo lo siguiente pero que no de error?

Código PHP:
Ver original
  1. namespace A
  2. class A{
  3.     public function invoke($func){
  4.         //de esta manera
  5.         //(da error porque espera un identificador, no una variable)
  6.         return \B\${func}();
  7.        //o de esta otra manera
  8.         return \B\$func();
  9.     }
  10. }

El propósito es no tener que usar una función al margen de una clase para tener que incluir el archivo y que el código quede más legible utilizando el namespace de la función. ¿Se llama performance ?

Saludos.
__________________
Ayúdame a hacerlo por mi mismo.

Última edición por guardarmicorreo; 22/02/2015 a las 09:29
  #2 (permalink)  
Antiguo 22/02/2015, 13:47
Avatar de pateketrueke
Modernizr
 
Fecha de Ingreso: abril-2008
Ubicación: Mexihco-Tenochtitlan
Mensajes: 26.399
Antigüedad: 16 años, 7 meses
Puntos: 2534
Respuesta: ¿Pasar un identificador de una funcion a variable e incluirla en una sente

Por favor lee el manual acerca de namespaces, variables y funciones.

Tu problema tiene que ver más con el uso de variables que aproximen valores usables, como funciones o instancias de clase.

El tema es que tratas de devolver cadenas que por arte de magia se intenten evaluar en otros contextos: y eso no funciona sólo porque lo pienses así.

Primero debes entender como funcionan las variables al respecto:
Código PHP:
Ver original
  1. function foo() {
  2.   return 'bar';
  3. }
  4.  
  5. $x = 'foo';
  6.  
  7. echo $x(); // bar

Eso funciona así en el contexto global, sin embargo:
Código PHP:
Ver original
  1. // MAL
  2. $x = '\\A\\a()';
  3.  
  4. echo $x();
  5.  
  6. // BIEN
  7. $x = '\\A\\a';
  8.  
  9. echo $x();
  10.  
  11. // equivalente
  12. echo call_user_func($x);
  13.  
  14. // así que podrías usar esto
  15. return call_user_func("\\B\\$func");

¿Por qué agregas parentesis en tus cadenas a evaluar?

Yo pienso que el error es ese, por favor consulta un manual al respecto.
__________________
Y U NO RTFM? щ(ºдºщ)

No atiendo por MP nada que no sea personal.
  #3 (permalink)  
Antiguo 23/02/2015, 09:03
Avatar de hhs
hhs
Colaborador
 
Fecha de Ingreso: junio-2013
Ubicación: México
Mensajes: 2.995
Antigüedad: 11 años, 4 meses
Puntos: 379
Respuesta: ¿Pasar un identificador de una funcion a variable e incluirla en una sente

complementando la respuesta de Pateketrueke
Código PHP:
Ver original
  1. namespace foo\bar {
  2.     function baz() {
  3.         return 'foo.bar.baz';
  4.     }
  5. }
  6.  
  7. namespace A {
  8.  
  9.     class A{
  10.         public function invoke($func){
  11.             return call_user_func($func);
  12.         }
  13.     }
  14.  
  15.     $obj = new A();
  16.     echo $obj->invoke('\foo\bar\baz');
  17.  
  18. }
__________________
Saludos
About me
Laraveles
A class should have only one reason to change.
  #4 (permalink)  
Antiguo 03/03/2015, 05:30
Avatar de guardarmicorreo  
Fecha de Ingreso: noviembre-2012
Ubicación: Córdoba
Mensajes: 1.153
Antigüedad: 12 años
Puntos: 84
Respuesta: ¿Pasar un identificador de una funcion a variable e incluirla en una sente

He leído el manual al respecto, y he entendido vuestras explicaciones, pero sigo sin poder hacerlo.

El caso es el siguiente.

-Desde el index llamo a un módulo y un método con o sin unos argumentos. Dicho index inicia el spl_autoload_register();

-Cada módulo tiene el namespace module, porque están en la carpeta module.

-Cada módulo instancia a otras clases utilizando los namespaces de otras clases y para presentar la información procesada instancia a un controlador frontend para que llame a su html correspondiente.

-Todos los html tienen el namespace html porque están en la carpeta html.

-Si quiero evitar tener que crear un archivo para cada html de un modulo (porque quiero poder representar varios casos de salida al usuario) en un mismo archivo debo establecer el namespace html y definir varias funciones.

-El problema está, en que cuando el frontend busca por el namespace html y la función dada no lo realiza.

Este es el código del frontcontroller

Código PHP:
Ver original
  1. <?php
  2. namespace controller;
  3. class FrontEnd{
  4.     public function invoke($func){
  5.         return call_user_func('\html\\'.$func);
  6.     }
  7. }
  8. ?>

El retorno es que la función no existe.
__________________
Ayúdame a hacerlo por mi mismo.
  #5 (permalink)  
Antiguo 03/03/2015, 05:36
Avatar de dashtrash
Colaborador
 
Fecha de Ingreso: abril-2007
Ubicación: Ni en Sevilla,ni en Sanlúcar..qué más da..
Mensajes: 927
Antigüedad: 17 años, 7 meses
Puntos: 270
Respuesta: ¿Pasar un identificador de una funcion a variable e incluirla en una sente

Código PHP:
Ver original
  1. namespace aa
  2. {
  3.   function p(){
  4.     echo "HOLA";
  5.   }
  6. }
  7.  
  8. namespace {
  9.    $f='\aa\p';
  10.    $f();  
  11. }
  #6 (permalink)  
Antiguo 03/03/2015, 05:39
Avatar de guardarmicorreo  
Fecha de Ingreso: noviembre-2012
Ubicación: Córdoba
Mensajes: 1.153
Antigüedad: 12 años
Puntos: 84
Respuesta: ¿Pasar un identificador de una funcion a variable e incluirla en una sente

Gracias dashtrash, pero esa lógica, no sé por qué pero, no me funciona a mi :S

He leído todo de namespace y call_user_func() y no logro entender por qué no funciona.
__________________
Ayúdame a hacerlo por mi mismo.
  #7 (permalink)  
Antiguo 03/03/2015, 05:50
Avatar de guardarmicorreo  
Fecha de Ingreso: noviembre-2012
Ubicación: Córdoba
Mensajes: 1.153
Antigüedad: 12 años
Puntos: 84
Respuesta: ¿Pasar un identificador de una funcion a variable e incluirla en una sente

Dejo el código tal cual lo tengo ahora mismo

modulo Find, se encuentra en la carpeta module y por lo tanto tiene el namespace modules
Código PHP:
Ver original
  1. <?php
  2. namespace module;
  3.  
  4. class Find{
  5.    
  6.     public function home(){
  7.         $obj = new \controller\FrontEnd();
  8.         return $obj->invoke(array('func'=>'home', 'args'=>NULL));
  9.     }
  10. }
  11. ?>

El código anterior instancia a el controlador frontend en caso de que el usuario sólo acceda a ese módulo (sirve para buscar un usuario en la base de datos por nombre, apellidos, documento de identidad, telefono, etc.).

Este es el código del controlador frontend

Código PHP:
Ver original
  1. <?php
  2. namespace controller;
  3. class FrontEnd{
  4.     public function invoke($args){
  5.         //esta es la línea 18
  6.         return \call_user_func('\html\\'.$args['func'], $args['args']);
  7.     }
  8. }
  9. ?>

Y la salida es esta

Cita:
Warning: call_user_func() expects parameter 1 to be a valid callback, function '\html\home' not found or invalid function name in /srv/www/htdocs/tiendainformatica/controller/frontend.php on line 18
Entiendo lo que me decís, pero en este caso no sé por qué pero me devuelve esa salida :S
__________________
Ayúdame a hacerlo por mi mismo.
  #8 (permalink)  
Antiguo 03/03/2015, 07:06
Avatar de dashtrash
Colaborador
 
Fecha de Ingreso: abril-2007
Ubicación: Ni en Sevilla,ni en Sanlúcar..qué más da..
Mensajes: 927
Antigüedad: 17 años, 7 meses
Puntos: 270
Respuesta: ¿Pasar un identificador de una funcion a variable e incluirla en una sente

Y seguro que existe la *funcion* '\html\home'? No es una clase o un método? Porque ese es el error que da.
  #9 (permalink)  
Antiguo 03/03/2015, 07:30
Avatar de guardarmicorreo  
Fecha de Ingreso: noviembre-2012
Ubicación: Córdoba
Mensajes: 1.153
Antigüedad: 12 años
Puntos: 84
Respuesta: ¿Pasar un identificador de una funcion a variable e incluirla en una sente

Sí, existe, este es el documento php

Código PHP:
Ver original
  1. <?php
  2. namespace html;
  3. function home($args=NULL){
  4.     ?>
  5. resultados
  6. <?php
  7. }
  8. function find($args=NULL){
  9.     ?>
  10. encontrado
  11. <?php
  12. }
  13.  
  14. function nofind($args=NULL){
  15.     ?>
  16. no encontrado
  17. <?php
  18. }

Pensé que el error debía ser porque había otro documento en el directorio html que tenía la funcion home(), así que cambié el nombre, ejecuté, y el error persiste exactamente igual.

En el directorio html hay otras funciones, que no se llama ninguna home() y que no tienen namespace definido.
__________________
Ayúdame a hacerlo por mi mismo.
  #10 (permalink)  
Antiguo 03/03/2015, 09:09
Avatar de dashtrash
Colaborador
 
Fecha de Ingreso: abril-2007
Ubicación: Ni en Sevilla,ni en Sanlúcar..qué más da..
Mensajes: 927
Antigüedad: 17 años, 7 meses
Puntos: 270
Respuesta: ¿Pasar un identificador de una funcion a variable e incluirla en una sente

Entonces lo que ocurre es que no se ha incluido ese fichero.Haz un "echo" al final del fichero donde está la funcion home, y mira a ver si se muestra antes de que se ejecute call_user_func
  #11 (permalink)  
Antiguo 03/03/2015, 13:07
Avatar de guardarmicorreo  
Fecha de Ingreso: noviembre-2012
Ubicación: Córdoba
Mensajes: 1.153
Antigüedad: 12 años
Puntos: 84
Respuesta: ¿Pasar un identificador de una funcion a variable e incluirla en una sente

Cita:
Iniciado por dashtrash Ver Mensaje
Entonces lo que ocurre es que no se ha incluido ese fichero.Haz un "echo" al final del fichero donde está la funcion home, y mira a ver si se muestra antes de que se ejecute call_user_func
¿Te refieres a que haga esto?

Código PHP:
Ver original
  1. <?php
  2. namespace html;
  3. function home($args=NULL){
  4.     ?>
  5. resultados
  6. <?php
  7. }
  8. function find($args=NULL){
  9.     ?>
  10. encontrado
  11. <?php
  12. }
  13.  
  14. function nofind($args=NULL){
  15.     ?>
  16. no encontrado
  17. <?php
  18. //
  19. // aquí pongo el echo?
  20. echo "hola mundo";
  21. //
  22. //
  23. }
__________________
Ayúdame a hacerlo por mi mismo.
  #12 (permalink)  
Antiguo 03/03/2015, 17:46
Avatar de dashtrash
Colaborador
 
Fecha de Ingreso: abril-2007
Ubicación: Ni en Sevilla,ni en Sanlúcar..qué más da..
Mensajes: 927
Antigüedad: 17 años, 7 meses
Puntos: 270
Respuesta: ¿Pasar un identificador de una funcion a variable e incluirla en una sente

Eso es...Se llega a mostrar el echo?
Si pones otro echo en call_user_func, cual se muestra primero?
  #13 (permalink)  
Antiguo 03/03/2015, 17:56
Avatar de guardarmicorreo  
Fecha de Ingreso: noviembre-2012
Ubicación: Córdoba
Mensajes: 1.153
Antigüedad: 12 años
Puntos: 84
Respuesta: ¿Pasar un identificador de una funcion a variable e incluirla en una sente

He puesto el echo que me has dicho y en el frontend esto otro

Código PHP:
Ver original
  1. class FrontEnd{
  2.     public function invoke($args){
  3.         echo "mundo";
  4.         echo \call_user_func('\html\\'.$args['func'], $args['args']);
  5.     }

Y me muestra lo siguiente

Cita:
mundo
Warning: call_user_func() expects parameter 1 to be a valid callback, function '\html\home' not found or invalid function name in /srv/www/htdocs/tiendainformatica/controller/frontend.php on line 19
¿Significa que para las funciones tengo que hacer include o require del documento dónde se encuentra la función mientras que con las clases no? ¿el include/require lo debería agregar al spl_autoload_register()?
__________________
Ayúdame a hacerlo por mi mismo.
  #14 (permalink)  
Antiguo 03/03/2015, 18:09
Avatar de pateketrueke
Modernizr
 
Fecha de Ingreso: abril-2008
Ubicación: Mexihco-Tenochtitlan
Mensajes: 26.399
Antigüedad: 16 años, 7 meses
Puntos: 2534
Respuesta: ¿Pasar un identificador de una funcion a variable e incluirla en una sente

Cita:
¿el include/require lo debería agregar al spl_autoload_register()?
Creo que deberías leer el manual más a menudo.

La implementación de spl_autoload_register() sirve únicamente para clases, no para funciones ni para otros scripts más simples.
__________________
Y U NO RTFM? щ(ºдºщ)

No atiendo por MP nada que no sea personal.
  #15 (permalink)  
Antiguo 04/03/2015, 01:58
Avatar de guardarmicorreo  
Fecha de Ingreso: noviembre-2012
Ubicación: Córdoba
Mensajes: 1.153
Antigüedad: 12 años
Puntos: 84
Respuesta: ¿Pasar un identificador de una funcion a variable e incluirla en una sente

¿Entonces no me queda más remedio que meter el html en un metodo de una clase para poder utilizar los namespaces? :S
__________________
Ayúdame a hacerlo por mi mismo.
  #16 (permalink)  
Antiguo 04/03/2015, 04:11
Avatar de dashtrash
Colaborador
 
Fecha de Ingreso: abril-2007
Ubicación: Ni en Sevilla,ni en Sanlúcar..qué más da..
Mensajes: 927
Antigüedad: 17 años, 7 meses
Puntos: 270
Respuesta: ¿Pasar un identificador de una funcion a variable e incluirla en una sente

Cita:
Iniciado por guardarmicorreo Ver Mensaje
¿Entonces no me queda más remedio que meter el html en un metodo de una clase para poder utilizar los namespaces? :S
El que el autoload se disspare con accesos a clases, y tú estés utilizando funciones, es una cosa, y que PHP requiera clases para usar namespaces es otra.
Lo que tienes que cambiar es la forma en la que cargas todos los requisitos necesarios antes de llamar a la función.No puedes usar autoload para eso.Tienes que hacer include, antes de llamar a call_user_func. Si dado un método, conoces el namespace en el que está, (html), posiblemente también puedas derivar en qué fichero se encuentra.Tienes que hacer el include del fichero manualmente antes de invocar la función.
  #17 (permalink)  
Antiguo 04/03/2015, 05:52
Avatar de guardarmicorreo  
Fecha de Ingreso: noviembre-2012
Ubicación: Córdoba
Mensajes: 1.153
Antigüedad: 12 años
Puntos: 84
Respuesta: ¿Pasar un identificador de una funcion a variable e incluirla en una sente

Entiendo. Entonces la única solución es incluir el archivo con una función externa a la clase y ahí ya utilizar la función del archivo incluido

Código PHP:
Ver original
  1. namespace controller;
  2.  
  3. /*
  4.     funcion para incluir el html
  5.  *  */
  6. function load($file){
  7.     include "html/${file}.php";
  8. }
  9.  
  10. /*
  11.     llama al html y lo retorna
  12.  *  */
  13. class FrontEnd{
  14.     public function invoke($args){
  15.         load($args['file']);
  16.         return ${args}['func']($args['args']);
  17.  
  18.         //esto ya no sirve
  19.         //return \call_user_func('\html\\'.$args['func'], $args['args']);
  20.     }
  21. }

Quería tenerlo todo encapsulado en clases, pero entonces tendré que aceptar que no es posible.

Mil y muchas gracias por la ayuda de los 3! :P

Un saludo! :D
__________________
Ayúdame a hacerlo por mi mismo.
  #18 (permalink)  
Antiguo 04/03/2015, 06:58
Avatar de dashtrash
Colaborador
 
Fecha de Ingreso: abril-2007
Ubicación: Ni en Sevilla,ni en Sanlúcar..qué más da..
Mensajes: 927
Antigüedad: 17 años, 7 meses
Puntos: 270
Respuesta: ¿Pasar un identificador de una funcion a variable e incluirla en una sente

Código PHP:
Ver original
  1. namespace controller;
  2.  
  3. /*
  4.     llama al html y lo retorna
  5.  *  */
  6. class FrontEnd{
  7.     public function invoke($args){
  8.         include "html/".$args['file'].".php";
  9.         return ${args}['func']($args['args']);
  10.  
  11.         //esto ya no sirve
  12.         //return \call_user_func('\html\\'.$args['func'], $args['args']);
  13.     }
  14. }
La cuestión es que el autoload no se va a llamar si una funcion no está definida.
Por lo que tienes que hacer el include.
El include lo haces donde te haga falta, no tiene por qué ser en una función.
  #19 (permalink)  
Antiguo 04/03/2015, 11:19
Avatar de guardarmicorreo  
Fecha de Ingreso: noviembre-2012
Ubicación: Córdoba
Mensajes: 1.153
Antigüedad: 12 años
Puntos: 84
Respuesta: ¿Pasar un identificador de una funcion a variable e incluirla en una sente

Muchas gracias dashtrash! es que el include al tratarlo así en una ocasión me daba problemas, por eso no lo volví a utilizar así. He aplicado tal y cómo lo dices y efectivamente funciona.

Un saludo! :D
__________________
Ayúdame a hacerlo por mi mismo.

Etiquetas: funcion, html, identificador, 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 17:38.