← Voltar aos artigos

closures · callable · funções · tipos

Closure vs callable no PHP: qual a diferença e quando usar cada um

Publicado em 24/08/2026 · 9 min de leitura

A diferença cabe numa frase: callable é um tipo que descreve qualquer coisa que dá para chamar — o nome de uma função numa string, um par [objeto, 'método'], um objeto com __invoke, uma função anônima. Já Closure é uma classe concreta, o objeto que o PHP cria quando você escreve function () {} ou fn () =>. Daí a relação: todo Closure é callable, mas nem todo callable é Closure. Entender isso resolve de imediato três dúvidas práticas — por que public callable $cb;fatal error, por que $this->cb() não chama a sua closure, e o que a sintaxe strtoupper(...) do PHP 8.1 realmente faz.

As sete formas de callable

O jeito mais rápido de fixar a diferença é ver as formas lado a lado. Todas as sete abaixo funcionam em array_map, usort e qualquer parâmetro tipado como callable — mas só duas são objetos Closure:

1. Nome de função numa string

A forma mais antiga. É só uma string; o PHP resolve o nome na hora de chamar.

$c = 'strtoupper';
is_callable($c);          // true
$c instanceof Closure;    // false — é uma string!

2. Método estático (duas escritas)

Tanto o array [Classe::class, 'metodo'] quanto a string 'Classe::metodo' funcionam.

$c1 = [Fmt::class, 'up'];
$c2 = 'Fmt::up';
is_callable($c1);         // true
$c1 instanceof Closure;   // false — é um array

3. Método de instância

Um array com o objeto e o nome do método. Muito usado como callback.

$c = [$obj, 'low'];
is_callable($c);          // true
$c instanceof Closure;    // false — array de novo

4. Objeto com __invoke

Qualquer objeto cuja classe tenha o método mágico __invoke pode ser chamado como se fosse função.

class Fmt { public function __invoke($s) { return "[$s]"; } }
$obj = new Fmt;
$obj('oi');               // "[oi]"
$obj instanceof Closure;  // false — é um Fmt, não um Closure

5. Função anônima e arrow function

Só aqui o PHP cria um objeto da classe Closure. As duas formas produzem a mesma classe.

$c1 = function ($s) { return "<$s>"; };
$c2 = fn ($s) => "{{$s}}";
$c1 instanceof Closure;   // true
$c2 instanceof Closure;   // true

O resumo

Sete formas, todas is_callable() === true. Apenas duas são instanceof Closure. callable é a descrição; Closure é uma das implementações.

string | 'Classe::m' | [Classe,'m'] | [$obj,'m'] | __invoke   → callable, NÃO Closure
function () {} | fn () =>                                     → callable E Closure

Por que callable não pode ser tipo de propriedade

Aqui está a consequência prática mais concreta da diferença — e um erro que trava muita gente:

class Botao {
    public callable $aoClicar;   // Fatal error: Property Botao::$aoClicar
}                                // cannot have type callable

O motivo não é capricho: callable depende do contexto onde é resolvido. A string 'self::publico', por exemplo, só faz sentido dentro da classe que a escreveu; [$this, 'metodo'] depende do objeto atual; e a visibilidade importa — is_callable([$obj, 'metodoPrivado']) devolve true de dentro da classe e false de fora. Um valor cujo significado muda conforme quem olha não pode ser guardado numa propriedade com segurança, então o PHP simplesmente proíbe.

Closure, por ser uma classe comum, não tem esse problema: ele já é um objeto autocontido, com o escopo embutido.

evite
class Botao {
    public callable $aoClicar;        // Fatal error na hora de carregar a classe
}

// e mesmo em parâmetro, callable aceita qualquer coisa:
function registrar(callable $cb) { }
registrar('strtoupper');              // passa uma string —
                                      // você não pode chamar ->bindTo() nela
prefira
class Botao {
    public function __construct(
        public Closure $aoClicar,     // funciona, e garante um objeto
    ) {}
}

function registrar(Closure $cb) { }
registrar(strtoupper(...));           // convertido em Closure (PHP 8.1+)
registrar(fn () => null);             // sempre um objeto de verdade

A ponte: strtoupper(...) do PHP 8.1

Se Closure é o tipo mais seguro mas você tem um callable "velho" em mãos, existe uma conversão de uma linha. A first-class callable syntax (PHP 8.1) transforma qualquer callable num Closure — os ... são literais, você digita exatamente assim:

$f = strtoupper(...);        // Closure a partir de uma função
$g = $obj->low(...);         // Closure a partir de um método de instância
$h = Fmt::up(...);           // Closure a partir de um método estático

$f instanceof Closure;       // true

Antes do 8.1, o equivalente era Closure::fromCallable('strtoupper') — ainda funciona e é o que você usa em código que precisa rodar em PHP 7.1–8.0. A vantagem da sintaxe nova, além de mais curta, é que ela é resolvida em tempo de compilação: erro de digitação no nome do método vira erro na hora, não um callable inválido descoberto só quando alguém chama.

O que só o Closure oferece

Como Closure é uma classe, ele tem métodos — e é aí que ele deixa de ser "só uma função" e vira uma ferramenta:

Captura de escopo. Uma closure criada dentro de um método já vem com o $this embutido, sem você fazer nada:

class Carrinho {
    private array $itens = ['a', 'b', 'c'];
    public function contador(): Closure {
        return function () { return count($this->itens); };   // $this vem junto
    }
}
(new Carrinho)->contador()();   // 3 — acessa a propriedade privada

Reatribuir o $this com bindTo / call. Você pode "emprestar" uma closure para outro objeto, inclusive furando o encapsulamento — recurso valioso em testes:

$espiao = function () { return $this->itens; };
$espiao->call(new Carrinho);                        // ["a","b","c"]
Closure::bind($espiao, new Carrinho, Carrinho::class)();   // idem

Controle de captura com use. A closure clássica congela uma cópia do valor no momento em que é criada; com & ela acompanha a variável:

$x = 1;
$foto  = function () use ($x)  { return $x; };
$vivo  = function () use (&$x) { return $x; };
$x = 99;
$foto();   // 1   ← fotografou na criação
$vivo();   // 99  ← acompanha

A arrow function captura o escopo automaticamente (sem escrever use), mas sempre por valor — não existe captura por referência em fn () =>. Se você precisa que a variável externa mude junto, use a forma longa com use (&$x).

Por que class Botao { public callable $aoClicar; } gera um fatal error, enquanto public Closure $aoClicar; funciona?

Ver resposta

Resposta certa: Porque callable depende do contexto e não é um tipo válido para propriedades

O significado de um callable muda conforme onde ele é resolvido: 'self::metodo' só vale dentro da classe, [$this, 'm'] depende do objeto atual, e a visibilidade altera o resultado de is_callable(). Guardar isso numa propriedade e resolver depois, em outro escopo, seria ambíguo — então o PHP proíbe (Property X cannot have type callable). Closure não tem esse problema porque é um objeto que já carrega o escopo dentro de si.

Qual usar em cada lugar

Onde Use Por quê
Parâmetro de função pública/API callable Aceita todas as formas — mais flexível para quem chama
Parâmetro quando você vai usar bindTo/call Closure Só o objeto tem esses métodos
Propriedade de classe Closure callable é proibido (fatal error)
Retorno de função Closure callable como retorno pode devolver uma string — o chamador não pode confiar que é objeto
Converter um callable "velho" funcao(...) (8.1+) ou Closure::fromCallable() Vira um Closure de verdade
Chamar closure de propriedade ($this->cb)() $this->cb() procura um método
Verificar se dá para chamar is_callable($x) Cobre as sete formas; respeita visibilidade
Verificar se é objeto closure $x instanceof Closure Só as anônimas e arrow fn passam

A regra de bolso que resume o artigo: aceite callable na entrada (seja generoso com quem chama), guarde e devolva Closure (seja específico no que você garante) — e converta com (...) na fronteira entre os dois.

no manualCallables

A página do tipo callable lista todas as formas aceitas pelo PHP, com as regras de resolução e visibilidade de cada uma — inclusive as que estão sendo depreciadas.

estudar na árvore →
no manualClosure

A classe Closure tem métodos que transformam funções anônimas em ferramenta: bindTo, call, fromCallable. Vale ver a interface completa para entender o que só o objeto permite.

estudar na árvore →
no manualFirst class callable syntax

A sintaxe funcao(...) do PHP 8.1 é a ponte oficial entre os dois mundos. A página explica o que ela aceita, o que resolve em tempo de compilação e como se compara ao Closure::fromCallable().

estudar na árvore →

Leve o estudo além do artigo

O manual inteiro do PHP como uma jornada: progresso por tópico, anotações e leitura embutida.