PHP Arrays Associativos
Na aula Arrays Indexados, cada gaveta do array tinha um número: 0, 1, 2… Isso é ótimo para listas, mas péssimo para uma ficha de cadastro: quem vai lembrar que a idade está na gaveta 1 e a cidade na 2? O array associativo troca os números por nomes. Você associa cada valor a uma etiqueta: "nome", "idade", "cidade". É, de longe, o tipo de array mais usado no PHP: formulários, sessões, linhas do banco de dados e JSON chegam todos assim.
- O que é um par chave => valor e como criar um array associativo.
- Como ler, mudar, acrescentar e apagar itens pelo nome.
- Como saber se uma chave existe:
isset×array_key_exists(e por que onullfaz diferença). - Como percorrer o array com
foreach ($a as $chave => $valor). - Por que a chave
"1"vira o número1sozinha, e outras surpresas das chaves. - Que o PHP guarda os itens na ordem em que você os colocou.
A ideia: uma ficha com campos
Pense numa ficha de matrícula em papel. Ela tem campos com nome e, ao lado de cada um, o que foi preenchido:
| Campo (chave) | Preenchido (valor) |
|---|---|
"nome" | "Ana" |
"idade" | 29 |
"cidade" | "Recife" |
Para saber a cidade, você não pergunta "o que está na linha 3?", e sim "o que está no campo cidade?". É exatamente assim que um array associativo funciona. Outros nomes que você vai encontrar para a mesma ideia: dicionário (Python), mapa (Java), objeto (JavaScript), hash.
Criar e ler
<?php
$aluna = [
"nome" => "Ana",
"idade" => 29,
"cidade" => "Recife",
];
echo $aluna["nome"], " tem ", $aluna["idade"], " anos e mora em ", $aluna["cidade"], ".\n";
print_r($aluna);
- [ … ]
- Os colchetes criam o array, como antes.
- "nome"
- A chave: o nome do campo. Normalmente é uma string entre aspas.
- =>
- A "setinha dupla" (sinal de igual e maior, sem espaço entre eles). Lê-se "aponta para":
"nome"aponta para"Ana". - "Ana"
- O valor guardado naquela chave. Pode ser de qualquer tipo.
- ,
- Separa um par do outro. A vírgula depois do último par é opcional (e prática).
- $aluna["nome"]
- Lê o valor da chave
"nome": o nome do array e, entre colchetes, a chave com aspas.
$ php aluna.php
Ana tem 29 anos e mora em Recife.
Array
(
[nome] => Ana « no lugar dos números, os nomes das chaves
[idade] => 29
[cidade] => Recife
)
Alinhar as setas => com espaços, como no exemplo, é só estética: o PHP ignora esses espaços. Muita gente alinha porque fica mais fácil de ler.
Para o PHP, os dois são o mesmo tipo: array. A diferença está só nas chaves. Um array indexado é um array cujas chaves são 0, 1, 2… criadas automaticamente. Escrever ["arroz", "café"] é o mesmo que escrever [0 => "arroz", 1 => "café"]. Use o indexado para listas de coisas do mesmo tipo (vários produtos) e o associativo para os dados de uma coisa (um produto: nome, preço, estoque).
Mudar, acrescentar e apagar
Com chaves de nome, as três operações usam a mesma escrita: $array["chave"] = valor;. Se a chave já existe, o valor é trocado; se não existe, ela é criada.
<?php $aluna = ["nome" => "Ana", "idade" => 29]; $aluna["idade"] = 30; // a chave existe: troca $aluna["email"] = "ana@exemplo.com"; // a chave não existe: cria unset($aluna["nome"]); // apaga a chave e o valor print_r($aluna); echo count($aluna), "\n";
$ php mudar-assoc.php
Array
(
[idade] => 30
[email] => ana@exemplo.com
)
2
O count funciona igual: conta os pares. E o $aluna[] = … (colchetes vazios) também funciona aqui, mas cria uma chave numérica; você vai ver isso na seção sobre chaves.
Usar dentro de aspas duplas
Para colocar um valor no meio de um texto, há três jeitos:
<?php
$aluna = ["nome" => "Ana", "idade" => 29];
echo "Olá, $aluna[nome]!\n";
echo "Olá, {$aluna['nome']}! Você tem {$aluna['idade']} anos.\n";
echo "Olá, " . $aluna["nome"] . "!\n";
$ php interp.php Olá, Ana! Olá, Ana! Você tem 29 anos. Olá, Ana!
"$aluna[nome]": dentro das aspas duplas, a chave vai sem aspas. Funciona, mas só nessa situação, e confunde."{$aluna['nome']}": com chaves{ }em volta, a chave vai com aspas simples, como no resto do código. É a forma recomendada.- A concatenação com
.sempre funciona (aula Operadores de String).
O que não funciona é misturar: "$aluna['nome']", com aspas e sem as chaves, é erro de sintaxe (veja Quando dá errado). Os detalhes estão na aula Interpolação.
Crie a ficha de outra pessoa, acrescente uma chave "profissao" e mostre uma frase com os dados. Experimente também apagar uma chave com unset e ver o print_r.
<?php
$pessoa = [
"nome" => "Bruno",
"idade" => 34,
"cidade" => "Olinda",
];
$pessoa["idade"] = 35;
$pessoa["profissao"] = "padeiro";
echo "{$pessoa['nome']} tem {$pessoa['idade']} anos e é {$pessoa['profissao']}.\n";
print_r($pessoa);
Uma chave que não existe
Pedir uma chave que não existe dá o mesmo aviso dos arrays indexados, agora com o nome da chave entre aspas:
<?php $aluna = ["nome" => "Ana", "idade" => 29]; echo "E-mail: ", $aluna["email"], "\n"; echo "E-mail: ", $aluna["email"] ?? "não informado", "\n"; echo $aluna["Nome"], "\n";
$ php chave-falta.php E-mail: Warning: Undefined array key "email" in /home/ana/site/chave-falta.php on line 3 E-mail: não informado Warning: Undefined array key "Nome" in /home/ana/site/chave-falta.php on line 5
- Linha 3: a chave
"email"não existe. Aviso, e o valor viranull. - Linha 4: com o
??, nenhum aviso: se a chave faltar, vale o texto da direita (aula ?? e ?->). - Linha 5:
"Nome"com N maiúsculo é outra chave. As chaves diferenciam maiúsculas de minúsculas.
Perguntar se a chave existe: isset e array_key_exists
Muitas vezes você precisa decidir algo conforme a chave exista ou não: "se o formulário mandou o e-mail, faça isso". Há duas funções para perguntar, e elas quase sempre respondem igual:
isset($a["chave"]): "está definido?" (is set). Respondetruese a chave existe e o valor não énull.array_key_exists("chave", $a): "a chave existe no array?". Respondetruese a chave existe, seja qual for o valor, aténull.
A diferença só aparece quando o valor guardado é null. Veja com uma ficha em que o telefone foi deixado em branco de propósito:
<?php
$aluna = ["nome" => "Ana", "telefone" => null];
var_dump(isset($aluna["nome"]));
var_dump(isset($aluna["email"]));
var_dump(isset($aluna["telefone"]));
var_dump(array_key_exists("nome", $aluna));
var_dump(array_key_exists("email", $aluna));
var_dump(array_key_exists("telefone", $aluna));
var_dump($aluna["telefone"] ?? "sem telefone");
$ php isset.php bool(true) bool(false) bool(false) « isset: a chave existe, mas vale null → false bool(true) bool(false) bool(true) « array_key_exists: a chave existe → true string(12) "sem telefone"
| Situação | isset($a["k"]) | array_key_exists("k", $a) | $a["k"] ?? "x" |
|---|---|---|---|
Chave existe, com valor ("Ana", 0, "", false) | true | true | o valor |
Chave existe, valor null | false | true | "x" |
| Chave não existe | false | false | "x" |
Qual usar?
issetno dia a dia: é curta, rápida e, na maioria dos casos, um valornullé mesmo "não tem nada". É a que você mais vai ver em formulários (isset($_POST["email"]), na aula $_GET e $_POST).array_key_existsquandonulltem significado e você precisa distinguir "o campo veio vazio" de "o campo nem veio".??quando você só quer um valor padrão. Ele segue a mesma regra doisset.
No isset você escreve o acesso inteiro: isset($aluna["email"]). No array_key_exists, primeiro a chave, depois o array: array_key_exists("email", $aluna). Trocar a ordem dá erro (veja Quando dá errado).
Percorrer com foreach
O foreach tem uma forma com duas variáveis, feita para arrays associativos: uma recebe a chave e a outra o valor, a cada volta. A Ana usa isso na tabela de preços da lojinha:
<?php
$precos = [
"café" => 18.9,
"pão" => 0.75,
"leite" => 5.49,
];
foreach ($precos as $produto => $preco) {
echo $produto, ": R$ ", number_format($preco, 2, ",", "."), "\n";
}
$total = 0;
foreach ($precos as $preco) {
$total += $preco;
}
echo "Total: R$ ", number_format($total, 2, ",", "."), "\n";
- foreach ($precos as $produto => $preco)
- "Para cada par de
$precos, coloque a chave em$produtoe o valor em$preco". A seta=>aqui tem o mesmo sentido da criação: chave à esquerda, valor à direita. Os nomes$produtoe$precosão escolha sua. - number_format($preco, 2, ",", ".")
- Escreve o número com 2 casas, vírgula decimal e ponto de milhar (aula Formatar Números).
- foreach ($precos as $preco)
- A forma curta, com uma variável só, recebe só os valores. Serve quando a chave não interessa, como na soma.
$ php foreach-assoc.php café: R$ 18,90 pão: R$ 0,75 leite: R$ 5,49 Total: R$ 25,14
Repare que o for com $i de 0 a count - 1, que funcionava nos arrays indexados, não serve aqui: não existe $precos[0]. Para arrays associativos, o caminho é sempre o foreach. (Para somar, existe ainda array_sum($precos), que você vai ver em Funções de Array, junto com array_keys e array_values, que pegam só as chaves ou só os valores.)
O que pode ser chave (e as conversões automáticas)
Uma chave só pode ser de dois tipos: int (número inteiro) ou string (texto). Se você usar outro tipo, ou uma string que "parece" um número inteiro, o PHP converte sozinho. Isso surpreende muita gente:
<?php
$a = [
"1" => "um",
"01" => "zero-um",
"1.5" => "um e meio",
"-5" => "menos cinco",
];
var_dump($a);
echo $a[1], " / ", $a["1"], "\n";
$ php chaves-conv.php
array(4) {
[1]=> « sem aspas: a string "1" virou o número 1
string(2) "um"
["01"]=> « com aspas: continua string ("01" não é a forma normal de escrever 1)
string(7) "zero-um"
["1.5"]=> « continua string: não é inteiro
string(9) "um e meio"
[-5]=> « "-5" virou o número -5
string(11) "menos cinco"
}
um / um « $a[1] e $a["1"] são a mesma gaveta
No var_dump, chave com aspas é string, chave sem aspas é número. A regra: uma string que é um inteiro escrito do jeito "normal" (sem zero à esquerda, sem +, sem espaço, sem ponto) vira int. Por isso "1" e 1 são a mesma chave, e o último a ser escrito vence:
<?php $a = ["cor" => "azul", "tamanho" => "M", "cor" => "verde"]; print_r($a); $b = ["1" => "a", 1 => "b"]; print_r($b);
$ php repetida.php
Array
(
[cor] => verde « a chave "cor" apareceu duas vezes: ficou o último valor
[tamanho] => M
)
Array
(
[1] => b « "1" e 1 são a mesma chave
)
Na prática, isso importa quando as chaves vêm de fora, como códigos de produto lidos de um formulário ou de um arquivo CSV: o código "1042" vira o número 1042, mas o código "0042" continua texto.
Os outros tipos também são convertidos, e o PHP 8.5 avisa nos casos mais perigosos:
| Você usa como chave | Vira | Aviso no PHP 8.5 |
|---|---|---|
"7" | 7 | nenhum |
"07", "7.0", " 7" | continuam strings | nenhum |
true / false | 1 / 0 | nenhum |
1.7 (float) | 1 (corta as decimais) | Deprecated: Implicit conversion from float 1.7 to int loses precision |
null | "" (string vazia) | Deprecated: Using null as an array offset is deprecated, use an empty string instead |
| um array ou um objeto | não pode | erro (TypeError) |
<?php $a = []; $a[1.7] = "x"; var_dump($a);
$ php chave-float.php
Deprecated: Implicit conversion from float 1.7 to int loses precision in /home/ana/site/chave-float.php on line 3
array(1) {
[1]=>
string(1) "x"
}
Deprecated quer dizer "desaprovado": funciona hoje, mas pode virar erro numa versão futura. Corrija quando ver um (mais em Tipos de Erro). A regra prática é simples: use como chave só strings ou inteiros.
Misturando chaves com nome e números
Um mesmo array pode ter as duas coisas. Os colchetes vazios [], e os itens sem chave, sempre pegam o maior número usado até ali + 1 (ou 0, se ainda não houver nenhum número):
<?php $a = [5 => "cinco", "nome" => "Ana", "seis?"]; $a[] = "mais um"; print_r($a); $b = ["a", "b"]; $b["x"] = "xis"; print_r($b);
$ php misto.php
Array
(
[5] => cinco
[nome] => Ana
[6] => seis? « sem chave: maior número (5) + 1
[7] => mais um
)
Array
(
[0] => a
[1] => b
[x] => xis
)
Funciona, mas é raro ser uma boa ideia. Prefira arrays que sejam claramente uma coisa ou outra: lista (chaves 0, 1, 2…) ou ficha (chaves com nome).
A ordem é a da inserção
Em algumas linguagens, um "dicionário" não tem ordem garantida. No PHP tem: os itens ficam na ordem em que foram colocados. Trocar o valor de uma chave que já existe não a muda de lugar.
<?php $notas = []; $notas["Pedro"] = 7.5; $notas["Ana"] = 9.0; $notas["Carla"] = 8.0; $notas["Ana"] = 9.5; // troca o valor; a Ana continua em 2º print_r($notas);
$ php ordem.php
Array
(
[Pedro] => 7.5
[Ana] => 9.5
[Carla] => 8 « 8.0 aparece como 8 no print_r
)
O PHP não ordena nada sozinho: nem por chave, nem por valor. Para colocar em ordem alfabética ou da maior nota para a menor, use as funções da aula Ordenar Arrays (ksort, arsort…).
Quando dá errado
Warning: Undefined array key "email"
$ php chave-falta.php E-mail: Warning: Undefined array key "email" in /home/ana/site/chave-falta.php on line 3
O que aconteceu: a chave não existe no array. Pode ser um erro de digitação ("emial"), maiúscula trocada ("Email") ou um dado que nem sempre vem, como um campo opcional de formulário.
Como resolver: confira as chaves que existem com print_r. Se o dado é opcional, use $a["email"] ?? "padrão" ou teste antes com isset.
Fatal error: Uncaught Error: Undefined constant "nome"
<?php $aluna = ["nome" => "Ana"]; echo $aluna[nome];
$ php semaspas.php
Fatal error: Uncaught Error: Undefined constant "nome" in /home/ana/site/semaspas.php:3
Stack trace:
#0 {main}
thrown in /home/ana/site/semaspas.php on line 3
O que aconteceu: fora das aspas duplas, uma palavra sem aspas e sem $ é lida como o nome de uma constante. Não existe constante nome, e o programa para. (Em PHPs muito antigos isso era só um aviso, por isso você ainda encontra $a[nome] em código velho.)
Como resolver: chave de texto sempre entre aspas: $aluna["nome"] ou $aluna['nome'].
Parse error: syntax error, unexpected string content ""
<?php $aluna = ["nome" => "Ana"]; echo "Olá, $aluna['nome']!\n";
$ php aspasinterp.php Parse error: syntax error, unexpected string content "", expecting "-" or identifier or variable or number in /home/ana/site/aspasinterp.php on line 3
O que aconteceu: dentro de aspas duplas, a forma simples ($aluna[nome]) não aceita aspas na chave. A mensagem é confusa: o PHP diz que esperava um nome (identifier), uma variável ou um número entre os colchetes.
Como resolver: envolva com chaves: "Olá, {$aluna['nome']}!". Ou concatene: "Olá, " . $aluna["nome"] . "!".
Parse error: syntax error, unexpected token "="
<?php $aluna = ["nome" = "Ana"];
$ php igual.php Parse error: syntax error, unexpected token "=", expecting "]" in /home/ana/site/igual.php on line 2
O que aconteceu: dentro da criação do array, o que liga a chave ao valor é =>, não =. Também acontece com -> (seta simples, que é de objetos) ou com espaço no meio (= >).
Como resolver: ["nome" => "Ana"]. Lembre: = é para guardar numa variável; => é para ligar chave e valor.
array_key_exists(): Argument #2 ($array) must be of type array, string given
<?php $aluna = ["nome" => "Ana"]; var_dump(array_key_exists($aluna, "email"));
$ php existe.php
Fatal error: Uncaught TypeError: array_key_exists(): Argument #2 ($array) must be of type array, string given in /home/ana/site/existe.php:3
Stack trace:
#0 {main}
thrown in /home/ana/site/existe.php on line 3
O que aconteceu: os argumentos foram trocados. O argumento nº 2 (chamado $array) deve ser um array, mas recebeu a string "email". TypeError é "erro de tipo": um valor do tipo errado foi passado a uma função (mais em Tipos e Retorno).
Como resolver: array_key_exists("email", $aluna): primeiro a chave, depois o array.
Referência rápida
| Você quer… | Código |
|---|---|
| Criar | $a = ["nome" => "Ana", "idade" => 29]; |
| Ler | $a["nome"] |
| Ler com valor padrão | $a["email"] ?? "não informado" |
| Mudar ou acrescentar | $a["idade"] = 30; |
| Apagar | unset($a["idade"]); |
| Existe e não é null? | isset($a["email"]) |
| Existe (mesmo que null)? | array_key_exists("email", $a) |
| Quantos pares | count($a) |
| Percorrer | foreach ($a as $chave => $valor) { … } |
| Usar num texto | "Olá, {$a['nome']}" |
| Só as chaves / só os valores | array_keys($a) / array_values($a) (em Funções de Array) |
Missão final
Missão: o estoque da lojinha da Ana está num array associativo. (1) Acrescente o produto "açúcar" com 7 unidades. (2) Mude o "leite" para 15. (3) Complete o foreach para mostrar uma linha produto: quantidade para cada item. (4) A última parte usa $estoque["arroz"] e gera um aviso: troque o teste por array_key_exists (ou isset) para mostrar Sem arroz no cadastro sem aviso nenhum.
<?php
$estoque = ["café" => 12, "pão" => 40, "leite" => 0];
// (1) e (2) aqui
foreach ($estoque as /* (3) */) {
echo "\n";
}
if ($estoque["arroz"]) {
echo "Tem arroz\n";
} else {
echo "Sem arroz no cadastro\n";
}
<?php
$estoque = ["café" => 12, "pão" => 40, "leite" => 0];
$estoque["açúcar"] = 7;
$estoque["leite"] = 15;
foreach ($estoque as $produto => $quantidade) {
echo "$produto: $quantidade\n";
}
if (array_key_exists("arroz", $estoque)) {
echo "Tem arroz\n";
} else {
echo "Sem arroz no cadastro\n";
}
A saída esperada, no PHP de verdade:
$ php estoque.php café: 12 pão: 40 leite: 15 « mudou de valor, mas continua no 3º lugar açúcar: 7 « o novo item entra no fim Sem arroz no cadastro
Exercícios
1. A setinha
Complete o símbolo que liga a chave ao valor:
2. Chave e valor no foreach
Complete para $campo receber a chave e $valor o valor:
3. Existe, mesmo que vazio?
Complete com a função que responde true mesmo quando o valor guardado é null:
4. Com $a = ["x" => null];, quanto vale isset($a["x"])?
5. Quantos itens tem ["1" => "a", 1 => "b", "01" => "c"]?
6. Qual linha mostra Olá, Ana sem erro, sendo $u = ["nome" => "Ana"]?
Resumo
- No array associativo, cada valor tem uma chave com nome:
["nome" => "Ana"]. Leia com$a["nome"]. $a["chave"] = valor;troca (se existe) ou cria (se não existe).unsetapaga.- Chave que não existe:
Warning: Undefined array key "…". As chaves diferenciam maiúsculas. issetéfalsepara valornull;array_key_existssó olha se a chave existe.foreach ($a as $chave => $valor)percorre os pares, na ordem em que foram inseridos.- Chaves são só
intoustring;"1"vira1,truevira1, e float enullgeramDeprecated. - Em texto:
"{$a['nome']}". Fora dele, a chave sempre entre aspas.