Me gustaría poder llamar a un cierre que asigno a la propiedad de un objeto directamente sin reasignar el cierre a una variable y luego llamarlo. es posible?
El siguiente código no funciona y causa Fatal error: Call to undefined method stdClass::callback()
.
$obj = new stdClass();
$obj->callback = function() {
print "HelloWorld!";
};
$obj->callback();
php
object
properties
closures
Kendall Hopkins
fuente
fuente
Respuestas:
A partir de PHP7, puede hacer
o use Closure :: call () , aunque eso no funciona en un
StdClass
.Antes de PHP7, tendría que implementar el
__call
método mágico para interceptar la llamada e invocar la devolución de llamada (lo cual no es posible, porStdClass
supuesto, porque no puede agregar el__call
método)Tenga en cuenta que no puede hacer
en el
__call
cuerpo, porque esto se dispararía__call
en un bucle infinito.fuente
Puede hacer esto llamando a __invoke en el cierre, ya que ese es el método mágico que usan los objetos para comportarse como funciones:
Por supuesto, eso no funcionará si la devolución de llamada es una matriz o una cadena (que también pueden ser devoluciones de llamada válidas en PHP), solo para cierres y otros objetos con comportamiento __invoke.
fuente
call_user_func($obj->callback)
no está tan mal.call_user_func
funciona con cadenas y eso no siempre es conveniente$obj->callback->__invoke();
cuando uno esperaría que fuera$obj->callback()
. Es solo una cuestión de coherencia.$obj->callback instanceof \Closure
.A partir de PHP 7 , puede hacer lo siguiente:
fuente
Desde PHP 7, se puede llamar a un cierre usando el
call()
método:Dado que PHP 7 también es posible ejecutar operaciones en
(...)
expresiones arbitrarias (como lo explica Korikulum ):Otros enfoques comunes de PHP 5 son:
usando el método mágico
__invoke()
(como lo explica Brilliand )usando la
call_user_func()
funciónusando una variable intermedia en una expresión
Cada camino tiene sus pros y sus contras, pero la solución más radical y definitiva sigue siendo la que presenta Gordon .
fuente
Parece ser posible usar
call_user_func()
.aunque no es elegante ... Lo que dice @Gordon es probablemente el único camino a seguir.
fuente
Bueno, si realmente insistes. Otra solución alternativa sería:
Pero esa no es la mejor sintaxis.
Sin embargo, el intérprete PHP siempre trata
T_OBJECT_OPERATOR
,IDENTIFIER
,(
como llamada al método. Parece que no hay una solución alternativa para->
omitir la tabla de métodos y acceder a los atributos.fuente
Sé que esto es antiguo, pero creo que Traits maneja muy bien este problema si está utilizando PHP 5.4+
Primero, cree un rasgo que haga que las propiedades sean invocables:
Luego, puedes usar ese rasgo en tus clases:
Ahora, puede definir propiedades a través de funciones anónimas y llamarlas directamente:
fuente
bueno, debe enfatizarse que almacenar el cierre en una variable y llamar a la variable es en realidad (extrañamente) más rápido, dependiendo de la cantidad de la llamada, se vuelve bastante, con xdebug (medición tan precisa), estamos hablando de 1,5 (el factor, al usar una variable, en lugar de llamar directamente a __invoke. Así que en su lugar, simplemente almacene el cierre en una variable y llámelo.
fuente
Actualizado:
PHP> = 7:
PHP> = 5.4:
fuente
Call to undefined method AnyObject::callback()
(La clase AnyObject existe, por supuesto.)Aquí hay otra alternativa basada en la respuesta aceptada pero extendiendo stdClass directamente:
Ejemplo de uso:
Probablemente sea mejor usar
call_user_func
o__invoke
aunque.fuente
Si está utilizando PHP 5.4 o superior, puede vincular un invocable al alcance de su objeto para invocar un comportamiento personalizado. Entonces, por ejemplo, si tuviera que configurar lo siguiente ...
Y estabas operando en una clase como esa ...
Puede ejecutar su propia lógica como si estuviera operando desde dentro del alcance de su objeto
fuente
Observo que esto funciona en PHP5.5
Permite a uno crear una colección de cierres de objetos pseudo-objetos.
fuente