← Voltar aos artigos

referências · funções · arrays · objetos · memória

Passagem por valor vs por referência no PHP: o que o & faz

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

Quando você passa uma variável para uma função no PHP, ela recebe por padrão uma cópia do valor — mexer nessa cópia lá dentro não altera a sua variável original. Colocar um & antes do parâmetro muda isso: a função passa a receber a própria variável, e qualquer alteração feita lá dentro aparece fora. É essa a diferença inteira. O que confunde vem depois: arrays também são copiados (mesmo sendo "grandes"), e objetos parecem referência mas não são — uma distinção que só aparece num caso específico, e que este artigo demonstra na prática.

O básico: cópia vs a própria variável

function dobra(int $n): void { $n *= 2; }

$x = 5;
dobra($x);
echo $x;   // 5 — a função dobrou a CÓPIA dela, não o seu $x

O $n de dentro da função é uma variável nova, que começou com o mesmo valor. Ela vive e morre ali. Com o &, não existe variável nova: $n e $x passam a ser dois nomes para o mesmo valor na memória.

evite
function adicionarTaxa(float $valor): void {
    $valor = $valor * 1.1;   // altera só a cópia local
}

$preco = 100.0;
adicionarTaxa($preco);
echo $preco;   // 100 — nada mudou (bug silencioso)
prefira
function adicionarTaxa(float &$valor): void {
    $valor = $valor * 1.1;   // altera a variável de fora
}

$preco = 100.0;
adicionarTaxa($preco);
echo $preco;   // 110

Repare que o & fica na declaração da função, não na chamada. Passar & na hora de chamar (adicionarTaxa(&$preco)) foi removido do PHP na versão 5.4 e hoje é erro de sintaxe.

Arrays também são cópias (e isso não custa caro)

Aqui mora a primeira surpresa: no PHP, array é um valor, não um objeto. Ele é copiado como qualquer escalar:

function adicionar(array $lista): void { $lista[] = 99; }

$itens = [1, 2];
adicionar($itens);
echo json_encode($itens);   // [1,2] — o 99 morreu dentro da função

A reação natural é: "então passar um array grande por valor é lento, melhor usar & por performance". Não é. O PHP usa uma técnica chamada copy-on-write: ao copiar, ele não duplica nada — apenas marca que os dois nomes apontam para os mesmos dados. A duplicação só acontece se (e quando) alguém escrever. Medindo com um array de 200 mil itens:

$grande = range(1, 200000);

$copia = $grande;     // custo de memória: 0 bytes
$copia[0] = 'x';      // agora sim: +4,2 MB (duplicou de verdade)

Ou seja: se a função só o array, passar por valor é gratuito. Usar & "por otimização" numa função que não modifica nada não acelera nada — só torna o código mais difícil de entender. Referência é uma decisão de semântica (quero alterar o original?), nunca de performance.

Objetos: parecem referência, mas não são

Esta é a parte que gera mais confusão — e a explicação circula errada por aí. Objetos não são passados por referência. Eles são passados por valor, só que o valor de uma variável de objeto não é o objeto: é um identificador que aponta para ele (um handle). A cópia copia o identificador, e o identificador copiado aponta para o mesmo objeto.

Parece filigrana, mas produz um comportamento observável — e é assim que se prova:

1. Alterar uma propriedade: afeta o original

A função recebe uma cópia do identificador, mas ele aponta para o mesmo objeto. Mexer no objeto é visível de fora.

class Conta { public int $saldo = 100; }

function saca(Conta $c): void { $c->saldo -= 30; }

$conta = new Conta;
saca($conta);
echo $conta->saldo;   // 70  ← mudou!

2. Reatribuir o parâmetro: NÃO afeta o original

Aqui está a prova. Trocar $c por um objeto novo só troca a cópia do identificador, que é local. Sua variável lá fora continua apontando para o objeto antigo.

function troca(Conta $c): void {
    $c = new Conta;      // $c local passa a apontar para outro objeto
    $c->saldo = 0;
}

troca($conta);
echo $conta->saldo;   // 70  ← NÃO mudou

3. Com &, aí sim reatribui

Com referência, $c e $conta são o mesmo nome. Trocar um troca o outro.

function trocaRef(Conta &$c): void {
    $c = new Conta;
    $c->saldo = 0;
}

trocaRef($conta);
echo $conta->saldo;   // 0  ← agora mudou

A conclusão

Se objetos fossem realmente passados por referência, o passo 2 teria funcionado. Ele não funciona — logo, o que é copiado é o identificador, não o objeto. Você só precisa de & com objetos quando quer substituir o objeto inteiro, o que é raro.

// alterar estado  → não precisa de &
// substituir o objeto → precisa de &

Diagnóstico: essa função vai mexer na minha variável?

A resposta está sempre na assinatura: se o parâmetro tem &, a função pode alterar a sua variável. Sem &, não pode (exceto propriedades de objeto, pelo motivo acima). Vale saber que várias funções nativas recebem por referência e é por isso que "alteram sozinhas":

$nums = [3, 1, 2];
sort($nums);                      // sort(array &$array) — altera o original
echo json_encode($nums);          // [1,2,3]

preg_match('/(\d+)/', 'abc 42', $m);   // $m é preenchido por referência
echo json_encode($m);                  // ["42","42"]

sort, shuffle, array_push, array_shift, settype e o terceiro argumento de preg_match funcionam assim. Se uma função "não devolve nada" mas mexe nos seus dados, procure o & na documentação dela.

Uma consequência prática: parâmetro por referência exige uma variável, não um valor solto. Passar um literal dá erro:

function f(&$x) { $x = 1; }
f(5);
// Error: f(): Argument #1 ($x) could not be passed by reference

A armadilha clássica do foreach

Uma função recebe function processar(array $dados) (sem &) e faz $dados['status'] = 'ok';. Depois da chamada, o array de fora tem a chave status?

Ver resposta

Resposta certa: Não — arrays são copiados por valor; a alteração morre na função

Array no PHP é valor, não objeto — diferente de linguagens como Java ou JavaScript, onde array é referência. Sem &, a função trabalha numa cópia (que graças ao copy-on-write só é materializada nessa hora). Para o efeito persistir, a função precisa retornar o array modificado (o caminho recomendado) ou declarar array &$dados.

Quando usar & — e quando não usar

Use quando:

Evite quando:

A regra de bolso: prefira retornar; use & quando modificar o original for o propósito declarado da função, e deixe isso óbvio no nome.

Resumo de decisão

Situação Comportamento Precisa de &?
Escalar (int, string, bool) Cópia do valor Sim, para alterar o original
Array Cópia do valor (copy-on-write) Sim, para alterar o original
Objeto — alterar propriedade Mesma instância Não
Objeto — substituir por outro A troca é local Sim
$b = $a com objetos Compartilham a instância Use clone para separar
Só ler um array grande Cópia custa 0 bytes Não (não é otimização)
Poderia retornar o resultado Não — prefira return

Em uma frase: o PHP copia valores, e o & desliga essa cópia — objetos só parecem exceção porque o que é copiado é o endereço deles, não o conteúdo.

no manualReferences Explained

A seção "References Explained" cobre o que uma referência realmente é no PHP (dois nomes para o mesmo valor), o que ela faz e o que ela não faz — inclusive por que referência não é ponteiro de C.

estudar na árvore →
no manualPassing by Reference

A página de passagem por referência detalha as regras dos parâmetros com &: o que pode ser passado, o que gera erro e como as funções nativas usam esse recurso.

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.