Menu
Coddy logo textTech

__call e __callStatic

Parte da seção Programação Orientada a Objetos do Journey de PHP da Coddy — lição 47 de 91.

Assim como __get() e __set() interceptam o acesso a propriedades, os métodos __call() e __callStatic() interceptam chamadas de métodos. Eles são acionados quando você chama um método que não existe ou está inacessível em um objeto ou classe.

O método __call() lida com chamadas de métodos de instância. Ele recebe o nome do método e um 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");

Saída:

Called 'sendEmail' with: Hello, World

Para chamadas de métodos estáticos, use __callStatic(). Observe que ele deve 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");

Saída:

Finding by Email: test@example.com

Estes métodos mágicos são poderosos para criar APIs fluentes, implementar o encaminhamento de métodos ou construir construtores de consultas dinâmicas (query builders) onde os nomes dos métodos se traduzem em operações de banco de dados. Eles permitem que seus objetos respondam de forma inteligente a qualquer chamada de método, mesmo aquelas que você não definiu explicitamente.

challenge icon

Desafio

Fácil

Vamos construir um cliente de API dinâmico que utiliza métodos mágicos para lidar com chamadas de métodos de forma flexível. Você criará uma classe que intercepta chamadas de métodos de instância e estáticos, traduzindo-as em respostas significativas do tipo API sem definir cada método explicitamente.

Você organizará seu código em dois arquivos:

  • ApiClient.php — Crie uma classe ApiClient que simula interações de API usando métodos mágicos. Sua classe deve ter uma propriedade privada $baseUrl definida através do construtor. Implemente dois métodos mágicos:
    • __call() — Lida com chamadas de métodos de instância. Quando um método que começa com get é chamado (como getUsers ou getPosts), extraia o nome do recurso (a parte após "get") e retorne "GET [baseUrl]/[resource]: [arguments joined by comma]". O nome do recurso deve ser convertido para minúsculas. Se o método não começar com "get", retorne "Unknown action: [methodName]".
    • __callStatic() — Lida com chamadas de métodos estáticos. Quando um método que começa com create é chamado (como createUser), extraia o nome do recurso e retorne "POST /[resource]: [arguments joined by comma]". O nome do recurso deve estar em minúsculas. Para métodos que começam com delete, retorne "DELETE /[resource]: [first argument]". Para qualquer outro método, retorne "Static action not supported: [methodName]".
  • main.php — Inclua o arquivo ApiClient. Você receberá três entradas: uma URL base, um identificador de recurso e um valor. Crie uma instância de ApiClient com a URL base. Em seguida, imprima quatro linhas:
    • Chame um método get dinâmico usando o identificador de recurso como sufixo do nome do método (por exemplo, se o recurso for "Users", chame getUsers) com o valor como argumento
    • Chame getProducts com dois argumentos: "electronics" e "active"
    • Chame o método estático createOrder com o valor como argumento
    • Chame o método estático deleteItem com o identificador de recurso como argumento

Os métodos mágicos permitem que seu cliente de API responda a qualquer chamada de método dinamicamente. Em vez de definir getUsers(), getPosts(), getProducts() e dezenas de outros, um único método __call() lida com todos eles examinando o nome do método e extraindo a informação relevante.

Folha de consulta

O método __call() intercepta chamadas de métodos de instância que não existem ou estão inacessíveis. Ele recebe o nome do método e um 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");
// Saída: Called 'sendEmail' with: Hello, World

O método __callStatic() intercepta chamadas de métodos estáticos. Ele deve 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");
// Saída: Finding by Email: test@example.com

Esses métodos mágicos são úteis para criar APIs fluentes, implementar o encaminhamento de métodos ou construir construtores de consultas dinâmicas onde os nomes dos métodos se traduzem em operações.

Experimente você mesmo

<?php

require_once 'ApiClient.php';

// Ler entradas
$baseUrl = trim(fgets(STDIN));
$resource = trim(fgets(STDIN));
$value = trim(fgets(STDIN));

// TODO: Criar uma instância do ApiClient com a URL base

// TODO: Chamar um método get dinâmico usando o recurso como sufixo do nome do método
// Dica: Use chamadas de método variáveis como $api->{"get" . $resource}($value)

// TODO: Chamar getProducts com dois argumentos: "electronics" e "active"

// TODO: Chamar o método estático createOrder com o valor como argumento
// Dica: Use ApiClient::createOrder($value)

// TODO: Chamar o método estático deleteItem com o recurso como argumento

?>
quiz iconTeste seus conhecimentos

Esta lição inclui um quiz rápido. Comece a lição para respondê-lo e acompanhar seu progresso.

Todas as lições de Programação Orientada a Objetos