Todos los lenguajes incorporan herramientas para hacer frente a diversos tipos de situaciones, algunas comunes, otras absurdas y otras poco usadas, como el método mágico __invoke().

Si recordamos hace menos de un mes hablamos sobre las funciones anónimas en el blog, en ese artículo se explicaba como poder usar una variable como una función, que aunque no es muy usado se puede dar el caso. Pues el método invoke sirve precisamente para controlar el comportamiento cuando llaman a nuestro objeto como si fuera una función.

Si no incluimos __invoke() en el objeto y lo llamamos como si fuera una función PHP mostrara un error, pero al definirlo podremos manipular tanto el objeto en si, como darle un comportamiento especifico, veamos un ejemplo:

En este ejemplo podemos ver que hay que instanciar el objeto para poder invocarlo como función, luego hemos definido que nuestro objeto devuelva un string al invocarlo, pero vamos a manipular también el contenido del objeto:

mensaje = $str; } } $clase = new MiClase(); echo $clase->mensaje; //Imprime: Mi Mensaje //Cambiamos el mensaje $clase('El nuevo mensaje'); echo $clase->mensaje; //Imprime: El nuevo mensaje ?>

En esta ocasión hemos alterado el contenido de un atributo del objeto al invocarlo como función.

Esto parece útil pero personalmente no sabría en que caso real aplicar esto, además no termina de convencerme porque da la sensación de romper la legibilidad del código orientado a objetos, pero bueno es una herramienta más que nos proporciona el lenguaje y que en algún momento podríamos usar.

El método mágico call si me parece útil en comparación con invoke. Y es que PHP nos permite controlar el comportamiento cuando llamamos a un método no accesible en el objeto, ¿esto que quiere decir? Pues que __call() entre en juego cuando tratamos de llamar a un método que no existe o a un método privado. Este método recibe dos parámetros, uno es el nombre del método al que se intenta invocar, y el otro los parámetros que le hemos pasado. Veamos un ejemplo intentando acceder a un método inexistente:

'" . $metodo . "', Parámetros -> '"; //Los parámetros se reciben en un array, para mostrarlos extraigo foreach($argumentos as $var){ $msg .= $var . "' "; } echo $msg; } } $clase = new MiClase(); $clase->miMetodo('hola',123); //Imprime: Se ha invocado un método inaccesible: Método -> 'miMetodo', Parámetros -> 'hola' 123' ?>

Bastante simple, también funciona cuando el método al que invocamos es privado:

'" . $metodo . "', Parámetros -> '"; //Los parámetros se reciben en un array, para mostrarlos extraigo foreach($argumentos as $var){ $msg .= $var . "' "; } echo $msg; } } $clase = new MiClase(); $clase->miMetodo('hola',123); //Imprime: Se ha invocado un método inaccesible: Método -> 'miMetodo', Parámetros -> 'hola' 123' ?>

¿Para qué nos sirve todo esto? Por ejemplo para gestionar errores de una clase concreta (aunque para eso deberíamos usar las excepciones), para permitir en situaciones excepcionales acceso a métodos privados (va en contra de la encapsulación), etcétera. Parece que a todas las situaciones que se me ocurren ahora mismo les encuentro una pega, pero estoy seguro de que hay situaciones en las que si es realmente útil usar __call(), es cuestión de darle a la cabeza.

También contamos con una variante de call para métodos estáticos: _callStatic(). Como te imaginaras debe ser definida como ‘static’ y su funcionamiento es exactamente igual que _call():

'" . $metodo . "', Parámetros -> '"; //Los parámetros se reciben en un array, para mostrarlos extraigo foreach($argumentos as $var){ $msg .= $var . "' "; } echo $msg; } static function __callStatic($metodo, $argumentos){ //Al llamar a un método inaccesible. $msg = "Se ha invocado un método estático inaccesible: Método -> '" . $metodo . "', Parámetros -> '"; //Los parámetros se reciben en un array, para mostrarlos extraigo foreach($argumentos as $var){ $msg .= $var . "' "; } echo $msg; } } MiClase::miMetodo('hola',123); //Imprime: Se ha invocado un método estático inaccesible: Método -> 'miMetodo', Parámetros -> 'hola' 123' ?>