__call y __callStatic
Parte de la sección Programación Orientada a Objetos del Journey de PHP de Coddy — lección 47 de 91.
Al igual que __get() y __set() interceptan el acceso a las propiedades, los métodos __call() y __callStatic() interceptan las llamadas a métodos. Se activan cuando llamas a un método que no existe o no es accesible en un objeto o clase.
El método __call() maneja llamadas a métodos de instancia. Recibe el nombre del método y un array de argumentos:
<?php
class Messenger {
public function __call(string $name, array $arguments): string {
return "Called '$name' with: " . implode(", ", $arguments);
}
}
$msg = new Messenger();
echo $msg->sendEmail("Hello", "World");
Salida:
Called 'sendEmail' with: Hello, WorldPara llamadas a métodos estáticos, utiliza __callStatic(). Ten en cuenta que debe declararse como static:
<?php
class QueryBuilder {
public static function __callStatic(string $name, array $arguments): string {
if (str_starts_with($name, "findBy")) {
$field = substr($name, 6);
return "Finding by $field: " . $arguments[0];
}
return "Unknown method: $name";
}
}
echo QueryBuilder::findByEmail("test@example.com");
Salida:
Finding by Email: test@example.comEstos métodos mágicos son potentes para crear APIs fluidas, implementar el reenvío de métodos o construir constructores de consultas dinámicas donde los nombres de los métodos se traducen en operaciones de base de datos. Permiten que tus objetos respondan de manera inteligente a cualquier llamada a un método, incluso a aquellos que no has definido explícitamente.
Desafío
FácilVamos a construir un cliente API dinámico que utiliza métodos mágicos para manejar llamadas a métodos de forma flexible. Crearás una clase que intercepte tanto las llamadas a métodos de instancia como estáticos, traduciéndolas en respuestas significativas de tipo API sin definir cada método explícitamente.
Organizarás tu código en dos archivos:
ApiClient.php— Crea una claseApiClientque simule interacciones de API utilizando métodos mágicos. Tu clase debe tener una propiedad privada$baseUrlestablecida a través del constructor. Implementa dos métodos mágicos:__call()— Maneja las llamadas a métodos de instancia. Cuando se llama a un método que comienza conget(comogetUsersogetPosts), extrae el nombre del recurso (la parte después de "get") y devuelve"GET [baseUrl]/[resource]: [arguments joined by comma]". El nombre del recurso debe convertirse a minúsculas. Si el método no comienza con "get", devuelve"Unknown action: [methodName]".__callStatic()— Maneja las llamadas a métodos estáticos. Cuando se llama a un método que comienza concreate(comocreateUser), extrae el nombre del recurso y devuelve"POST /[resource]: [arguments joined by comma]". El nombre del recurso debe estar en minúsculas. Para los métodos que comienzan condelete, devuelve"DELETE /[resource]: [first argument]". Para cualquier otro método, devuelve"Static action not supported: [methodName]".
main.php— Incluye el archivo ApiClient. Recibirás tres entradas: una URL base, un identificador de recurso y un valor. Crea una instancia deApiClientcon la URL base. Luego imprime cuatro líneas:- Llama a un método
getdinámico utilizando el identificador de recurso como sufijo del nombre del método (por ejemplo, si el recurso es "Users", llama agetUsers) con el valor como argumento. - Llama a
getProductscon dos argumentos:"electronics"y"active". - Llama al método estático
createOrdercon el valor como argumento. - Llama al método estático
deleteItemcon el identificador de recurso como argumento.
- Llama a un método
Los métodos mágicos permiten que tu cliente API responda a cualquier llamada a un método de forma dinámica. En lugar de definir getUsers(), getPosts(), getProducts() y docenas más, un único método __call() los maneja todos examinando el nombre del método y extrayendo la información relevante.
Hoja de referencia
El método __call() intercepta llamadas a métodos de instancia que no existen o no son accesibles. Recibe el nombre del método y un array de argumentos:
<?php
class Messenger {
public function __call(string $name, array $arguments): string {
return "Called '$name' with: " . implode(", ", $arguments);
}
}
$msg = new Messenger();
echo $msg->sendEmail("Hello", "World");
// Output: Called 'sendEmail' with: Hello, World
El método __callStatic() intercepta llamadas a métodos estáticos. Debe ser declarado como static:
<?php
class QueryBuilder {
public static function __callStatic(string $name, array $arguments): string {
if (str_starts_with($name, "findBy")) {
$field = substr($name, 6);
return "Finding by $field: " . $arguments[0];
}
return "Unknown method: $name";
}
}
echo QueryBuilder::findByEmail("test@example.com");
// Output: Finding by Email: test@example.com
Estos métodos mágicos son útiles para crear APIs fluidas, implementar el reenvío de métodos o construir constructores de consultas dinámicos donde los nombres de los métodos se traducen en operaciones.
Pruébalo tú mismo
<?php
require_once 'ApiClient.php';
// Leer entradas
$baseUrl = trim(fgets(STDIN));
$resource = trim(fgets(STDIN));
$value = trim(fgets(STDIN));
// TODO: Crear una instancia de ApiClient con la URL base
// TODO: Llamar a un método get dinámico usando el recurso como sufijo del nombre del método
// Sugerencia: Usar llamadas a métodos variables como $api->{"get" . $resource}($value)
// TODO: Llamar a getProducts con dos argumentos: "electronics" y "active"
// TODO: Llamar al método estático createOrder con el valor como argumento
// Sugerencia: Usar ApiClient::createOrder($value)
// TODO: Llamar al método estático deleteItem con el recurso como argumento
?>Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.
Todas las lecciones de Programación Orientada a Objetos
1Fundamentos de OOP
Archivos externosIntroducción a OOPClases vs ObjetosLa palabra clave $thisMétodosPropiedadesConstructor (__construct)Destructor (__destruct)Resumen - Calculadora simple4Herencia
Herencia básicaLa palabra clave parent::Sobrescritura de métodosLa palabra clave finalClases abstractasResumen - Jerarquía de empleados7Encapsulamiento
Público, Protegido, PrivadoModificadores de acceso a fondoGetters y SettersOcultamiento de informaciónPromoción de constructor (8.0)Resumen - Sistema de registros de estudiantes10Conceptos avanzados de POO
Composición vs. HerenciaInyección de dependenciasClases anónimasEnums (PHP 8.1)Fibers (PHP 8.1)Clonación de objetos a fondoGeneradores e Iteradores13Patrones de diseño Parte 2
Patrón CommandPatrón AdapterPatrón DecoratorPatrón Template MethodPatrón StatePatrón CompositePatrón Repository2Espacios de nombres y Autoloading
Introducción a los espacios de nombresLa palabra clave useEstándar de Autoloading PSR-4Autoloader de ComposerResumen - Proyecto organizado5Interfaces y Contratos
Introducción a las InterfacesImplementación de InterfacesImplementación de Múltiples InterfacesInterfaz vs Clase AbstractaType Hinting con InterfacesResumen - Calculadora de Formas8Métodos mágicos
Introducción a los métodos mágicos__toString y __debugInfo__get, __set, __isset, __unset__call y __callStatic__clone y clonación de objetos__serialize y __unserializeResumen - Colección personalizada3Propiedades de clase
Propiedades de instancia vs. estáticasConstantes en clasesMétodos y propiedades estáticosPropiedades privadas y protegidasPropiedades de solo lectura (PHP 8.1)Resumen - Gestor de cuenta bancaria6Polimorfismo
Sobrescritura de métodos revisadaPolimorfismo mediante interfacesType Hinting y tipos de uniónEnlace estático tardíoResumen - Procesador de pagos9Traits
Introducción a los TraitsUso de múltiples TraitsResolución de conflictos de TraitsMétodos abstractos en TraitsTraits frente a herencia12Patrones de diseño Parte 1
Introducción a los patrones de diseñoPatrón SingletonPatrón FactoryPatrón ObserverPatrón Strategy