Dia 1 — Fundamentos de PHP: PHP e MySQL
O que e PHP e onde ele roda
O que e PHP e onde ele roda
PHP e uma linguagem executada no servidor. O navegador pede uma página, o servidor roda o PHP, gera o HTML e so então envia a resposta. O código PHP nunca chega ao navegador: quem chega e o HTML montado por ele, visivel em "Exibir código-fonte".
O bloco <?php ?> e a mistura com HTML
O arquivo comeca com <?php e pode terminar com ?>. Fora desse bloco, tudo e HTML puro e não e executado. A mesma página pode misturar os dois: o PHP monta os dados e o HTML os exibe.
<p>Texto fixo no HTML.</p> <?php echo '<p>Texto montado pelo PHP.</p>'; ?>
Dentro do PHP as linhas não usam <p>, e sim echo. O <?= ?> e atalho de <?php echo ?> e existe desde o PHP 5.4.
Os quatro jeitos de instalar
| Opção | O que traz | Pasta do servidor | Quando usar |
|---|---|---|---|
| XAMPP | Apache + PHP + MySQL + phpMyAdmin | htdocs | Padrao do curso no Windows |
| Laragon | Apache + PHP + MySQL + terminal e editor | www | Ambiente completo e mais rapido |
| WAMP | Apache + PHP + MySQL, instalador proprio | www | Alternativa ao XAMPP |
| Online | PHP rodando no navegador do fornecedor | não se aplica | Primeiro teste, sem instalar nada |
O arquivo precisa terminar em
.phpe ficar dentro da pasta que o Apache aponta. No XAMPP eC:\xampp\htdocs; no Laragon e no WAMP,www.
Três erros que aparecem toda vez:
- Arquivo salvo como
teste.php.txt,teste.php~outeste.php(com espaco no fim). O navegador mostra o código em vez de executar, e parece que o PHP esta quebrado. - Arquivo na pasta errada. O Apache so entrega o que esta na pasta configurada; o caminho aparece na barra de endereco:
http://localhost/teste.php. - Servidor Apache parado. O painel do XAMPP mostra o botao "Start" em vermelho quando ele esta desligado.
O endereco localhost
localhost significa "esta propria maquina". O navegador não sai para a internet: ele pede a página para o Apache que roda na mesma maquina, e o Apache entrega o arquivo da pasta. Trocar localhost por 127.0.0.1 da o mesmo resultado.
O editor não importa: qualquer um serve, desde que salve como UTF-8 e com a extensao .php. Um arquivo PHP comeca a ser executado quando a primeira caractere depois da tag de abertura e algo executavel — um echo logo de cara evita páginas em branco.
Exemplo
<?php declare(strict_types=1); // Este arquivo e executado NO SERVIDOR. O navegador recebe somente o que // foi impresso, nunca estas linhas de codigo. echo "1. Onde este codigo esta rodando\n"; echo " tipo de servidor (sapi) : " . php_sapi_name() . "\n"; echo " versao do PHP : " . PHP_VERSION . "\n"; echo " arquivo em execucao : " . ($_SERVER['SCRIPT_NAME'] ?? '(desconhecido)') . "\n"; echo " pasta do arquivo : " . __DIR__ . "\n"; echo " memoria reservada : " . ini_get('memory_limit') . "\n"; // 2. O PHP monta o HTML e o navegador mostra o resultado. // Em "Exibir codigo-fonte" aparece a linha abaixo, nunca o PHP que a fez. echo "\n2. HTML que chega ao navegador (confira em Exibir codigo-fonte):\n"; echo '<p class="boas-vindas">Bem-vindo ao servidor local</p>' . "\n"; // 3. Fora de <?php ... ?> o arquivo e HTML puro: o servidor nao executa nada ali. ?> <!DOCTYPE html> <html lang="pt-BR"> <head> <meta charset="UTF-8"> <title>Teste do primeiro script</title> </head> <body> <p>Este paragrafo esta no arquivo como HTML literal.</p> <?php echo '<p>Este paragrafo foi montado pelo PHP.</p>'; ?> </body> </html>
Saída real
1. Onde este codigo esta rodando tipo de servidor (sapi) : cli versao do PHP : 8.3.35 arquivo em execucao : aula1.php pasta do arquivo : /w memoria reservada : 128M 2. HTML que chega ao navegador (confira em Exibir codigo-fonte): <p class="boas-vindas">Bem-vindo ao servidor local</p> o arquivo e HTML puro: o servidor nao executa nada ali. ?> <!DOCTYPE html> <html lang="pt-BR"> <head> <meta charset="UTF-8"> <title>Teste do primeiro script</title> </head> <body> <p>Este paragrafo esta no arquivo como HTML literal.</p> <p>Este paragrafo foi montado pelo PHP.</p></body> </html>
Escrevendo na tela: echo, print e comentários
Escrevendo na tela: echo, print e comentários
echo escreve um valor na página e e a instrução mais usada em PHP. Ela aceita varias expressoes separadas por virgula e não devolve nada. print faz quase o mesmo, mas aceita uma expressao so e devolve 1, o que permite usa-lo dentro de expressao.
As três formas de imprimir
echo— varias expressoes, mais rapido, devolve nada.print— uma expressao, devolve1, raramente usado.print_r()— mostra array e objeto de forma legivel; comtrueno segundo argumento devolve o texto em vez de imprimir.
echo $nome, ' tem ', 17, ' anos'; // varias expressoes print $nome; // uma expressao, devolve 1 print_r($notas); // imprime o array inteiro $texto = print_r($notas, true); // devolve string
Para debug, var_dump() mostra tipo e valor: e com ele que se descobre por que uma comparacao esta se comportando diferente do esperado.
Aspas duplas interpolam, aspas simples não
Dentro de aspas duplas o PHP resolve $variavel, {$variavel} e sequências como \n. Dentro de aspas simples nada e resolvido: nem variável, nem \n. E por isso que '$nome' mostra o cifrao escrito na tela.
Para quando a string tiver cifrao mas nenhuma interpolacao desejada, a forma mais segura e concatenar com o ponto, ou proteger a variável com barra: 'preco: \$' . $valor.
Comentarios
Três formas, todas dispensadas pelo servidor antes de gerar a página:
| Forma | Alcance | Uso |
|---|---|---|
// | até o fim da linha | o mais comum |
# | até o fim da linha | menos usado, igual ao // |
/* ... */ | varias linhas | cabecalho de arquivo, bloco desativado |
O comentario de bloco /* ... */ não aceita aninhamento: um /* dentro de outro /* fecha no primeiro */. Para desativar um trecho grande que já tem comentarios, use // em cada linha ou o atalho if (false) { ... }.
Texto que vem de fora precisa ser escapado
htmlspecialchars() troca por entidade os caracteres que o navegador interpretaria como HTML. Sem isso, um texto digitado pelo usuario pode montar uma tag e mudar a página. Ele deve ser aplicado na hora de exibir, não na de gravar.
htmlspecialchars($texto, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8');
O ENT_QUOTES cobre aspas simples e duplas; sem ele, as aspas simples passam. O ENT_SUBSTITUTE troca por entidade o caractere invalido em vez de devolver string vazia. E um valor de htmlspecialchars() deve sempre ir impresso com echo, nunca comparado.
Exemplo
<?php declare(strict_types=1); // echo aceita VARIAS expressoes separadas por virgula e nao devolve valor. $aluno = 'Maria'; echo "1. echo com varias expressoes: "; echo $aluno, ' tem ', 17, ' anos e foi aprovada.' . "\n"; // Concatenacao com o ponto tambem funciona com echo. echo ' Concatenado: ' . $aluno . ' - ' . 9.5 . PHP_EOL; // print aceita UMA expressao e devolve 1, o que permite usa-lo em expressao. print "2. print: $aluno foi aprovada\n"; // print_r mostra arrays e objetos de forma legivel. $notas = ['portugues' => 8.4, 'matematica' => 9.1, 'fisica' => 7.0]; echo "3. print_r de um array associativo:\n"; print_r($notas); // Com o segundo argumento true, print_r devolve a string em vez de imprimir. echo "4. print_r com true devolve texto: "; echo substr(print_r($notas, true), 0, 45) . "...\n"; // Interpolacao acontece apenas dentro de aspas duplas. echo "\n5. Com aspas duplas o PHP troca a variavel pelo valor: $aluno tem " . strlen($aluno) . " letras.\n"; // Com aspas simples tudo e literal: nem $aluno vira valor, nem \n vira quebra. echo '6. Com aspas simples e literal: $aluno e \n sao texto comum.' . "\n"; // Texto vindo de fora do programa precisa ser escapado antes de virar HTML. $comentario = '<b>"Produto"</b> & <script>alert(1)</script>'; echo "\n7. Texto cru: " . $comentario . "\n"; echo " Texto escapado: " . htmlspecialchars($comentario, ENT_QUOTES, 'UTF-8') . "\n"; // Comentario de uma linha com //, com #, e de varias linhas com /* */. // Nenhum deles aparece na pagina gerada. echo "\n8. Comentarios nao produzem saida nenhuma.\n";
Saída real
1. echo com varias expressoes: Maria tem 17 anos e foi aprovada.
Concatenado: Maria - 9.5
2. print: Maria foi aprovada
3. print_r de um array associativo:
Array
(
[portugues] => 8.4
[matematica] => 9.1
[fisica] => 7
)
4. print_r com true devolve texto: Array
(
[portugues] => 8.4
[matematic...
5. Com aspas duplas o PHP troca a variavel pelo valor: Maria tem 5 letras.
6. Com aspas simples e literal: $aluno e \n sao texto comum.
7. Texto cru: <b>"Produto"</b> & <script>alert(1)</script>
Texto escapado: <b>"Produto"</b> & <script>alert(1)</script>
8. Comentarios nao produzem saida nenhuma.
Variáveis e tipos de dado
Variáveis e tipos de dado
Toda variável comeca com $ e o PHP não exige declaracao de tipo antes: o tipo vem do valor atribuido. Nomes podem comecar com letra ou _, depois recebem letras, números e _, e diferenciam maiuscula de minuscula — $nota e $Nota são duas variáveis.
Os tipos do dia a dia
| Tipo | Para que serve | Como aparece no var_dump |
|---|---|---|
int | número inteiro | int(17) |
float | número com casas decimais | float(8.4) |
string | texto, entre aspas | string(5) "Maria" |
bool | verdadeiro ou falso | bool(true) |
null | variável sem valor | NULL |
array | lista ou dicionario de valores | array(2) {...} |
gettype($x) devolve o nome do tipo como string: "integer", "double", "string", "boolean", "NULL", "array". O var_dump() e melhor para diagnostico porque mostra o valor junto.
Conversao de tipo
O casting e explicito quando se escreve o tipo entre parenteses:
$texto = '42 itens'; (int) $texto; // 42 (float) '8.4'; // 8.4 (string) 17; // "17" (bool) '0'; // false
Sem casting, o proprio PHP converte o texto numerico na conta aritmetica: '42 itens' + 8 resulta em 50. Isso e conversao automatica, e não funciona com texto não numerico — 'abc' + 8 produz TypeError em PHP 8.
O tipo da variável não muda com a conversao automatica: $texto continua string depois do +.
Constantes
Constantes não usam $, não mudam durante a execução e valem em qualquer ponto do código. const vai no início do arquivo ou dentro de classe; define() pode ser chamado em tempo de execução.
const IVA = 0.18; define('FRETE_GRATIS_ACIMA_DE', 299.00); define('STATUS', 'ativo');
Para mostrar o valor de uma constante, use echo. Para mostrar tipo e valor, o var_dump() não funciona com constante; var_export(IVA, true) devolve '0.18'.
Nome de constante segue o mesmo padrao de variável, sem o $. Por convencao as constantes de verdade usam caixa alta com sublinhado: MAXIMO_DE_TENTATIVAS.
Exemplo
<?php declare(strict_types=1); // Nome de variavel: letra ou _ no inicio, depois letras, numeros ou _. // PHP diferencia maiuscula de minuscula: $nota e $Nota sao duas variaveis. $produto = 'Teclado mecanico'; $preco = 249.90; $quantidade = 3; $disponivel = true; $cupom = null; $tags = ['periferico', 'gamer', 'rgb']; // gettype devolve o nome do tipo como string. echo "1. gettype()\n"; echo ' produto -> ' . gettype($produto) . "\n"; echo ' preco -> ' . gettype($preco) . "\n"; echo ' quantidade -> ' . gettype($quantidade) . "\n"; echo ' disponivel -> ' . gettype($disponivel) . "\n"; echo ' cupom -> ' . gettype($cupom) . "\n"; echo ' tags -> ' . gettype($tags) . "\n"; // var_dump mostra tipo, valor e, em string, o numero de bytes. echo "\n2. var_dump()\n"; var_dump($produto, $preco, $cupom, $disponivel); // Casting explicito: (int), (float), (string), (bool), (array). echo "\n3. Conversao de tipo (casting)\n"; $texto = '42 itens'; var_dump((int) $texto, (float) '8.4', (string) 17, (bool) '0', (int) '12abc'); // Sem casting, o proprio PHP converte o texto numerico na conta — e avisa, // porque a string tem letras depois do numero. echo "\n4. Conversao automatica em expressao aritmetica\n"; echo ' $texto + 8 = ' . ((int) $texto + 8) . "\n"; echo ' "10" == 10 = ' . var_export('10' == 10, true) . "\n"; echo ' "10" === 10 = ' . var_export('10' === 10, true) . "\n"; // Constantes nao usam cifrao e nao mudam durante a execucao. const IVA = 0.18; define('FRETE_GRATIS_ACIMA_DE', 299.00); define('STATUS', 'ativo'); echo "\n5. Constantes: define() e const\n"; echo ' IVA = ' . IVA . "\n"; echo ' FRETE_GRATIS_ACIMA_DE = ' . FRETE_GRATIS_ACIMA_DE . "\n"; echo ' STATUS = ' . STATUS . "\n"; $subtotal = $preco * $quantidade; $total = $subtotal * (1 + IVA); echo ' subtotal (249,90 x 3) = ' . number_format($subtotal, 2, ',', '.') . "\n"; echo ' total com IVA de 18% = ' . number_format($total, 2, ',', '.') . "\n"; echo ' frete = ' . ($subtotal >= FRETE_GRATIS_ACIMA_DE ? 'gratis' : 'a calcular') . "\n";
Saída real
1. gettype() produto -> string preco -> double quantidade -> integer disponivel -> boolean cupom -> NULL tags -> array 2. var_dump() string(16) "Teclado mecanico" float(249.9) NULL bool(true) 3. Conversao de tipo (casting) int(42) float(8.4) string(2) "17" bool(false) int(12) 4. Conversao automatica em expressao aritmetica $texto + 8 = 50 "10" == 10 = true "10" === 10 = false 5. Constantes: define() e const IVA = 0.18 FRETE_GRATIS_ACIMA_DE = 299 STATUS = ativo subtotal (249,90 x 3) = 749,70 total com IVA de 18% = 884,65 frete = gratis
Comparação: == contra ===
Comparação: == contra ===
O == compara valores: se os tipos forem diferentes, o PHP converte um lado para o outro antes de decidir. O === compara tipo e valor ao mesmo tempo: so da verdadeiro quando os dois lados são do mesmo tipo e com o mesmo conteudo. Regra pratica: escreva ===.
A tabela completa dos tipos diferentes
| Comparacao | == | === | Por que |
|---|---|---|---|
17 e 17 | verdadeiro | verdadeiro | mesmo tipo e mesmo valor |
17 e '17' | verdadeiro | falso | texto numerico vira número |
1 e true | verdadeiro | falso | true vale 1 |
1.0 e true | verdadeiro | falso | 1.0 arredondado vale 1 |
'1' e true | verdadeiro | falso | '1' vira 1 e 1 vale true |
0 e '' | verdadeiro | falso | '' convertida em número vale 0 |
0 e '0' | verdadeiro | falso | '0' convertida em número vale 0 |
0 e false | verdadeiro | falso | false vale 0 |
'0' e false | verdadeiro | falso | '0' convertida em 0 |
0 e null | verdadeiro | falso | null vale 0 em contexto numerico |
0.0 e null | verdadeiro | falso | idem |
null e '' | verdadeiro | falso | '' convertida em null |
'abc' e 0 | verdadeiro | falso | 'abc' convertida em 0 (string não numerica) |
[] e false | verdadeiro | falso | array vazio vale false |
1 e 1.0 | verdadeiro | falso | int e float são tipos diferentes |
Em todas as linhas abaixo, === da falso. A conversao do == e sempre numérica quando os lados não batem, e e por isso que "17" casa com 17.
As negacoes
| Operador | Equivale a |
|---|---|
!= | negacao do == |
<> | apelido antigo do != — não usar |
!== | negacao do === |
O <> e sintaxe antiga e esta fora do manual de estilo; em código novo, escreva !=.
O caso que causa bug em formulario
Validar campo obrigatorio com == '' deixa passar o texto "0", que e numericamente zero:
if ($cep == '') { // "0" entra neste if: bug echo 'campo obrigatorio'; }
A forma correta não e comparar com string vazia, e testar o vazio de propósito:
$vazio = !isset($valor) || trim($valor) === '';
O !isset() cobre a variável ausente e o null; o trim($valor) === '' cobre a string em branco. Com isso o "0" e tratado como preenchimento, que e o que o usuario quis dizer.
Exemplo
<?php declare(strict_types=1); // Cada caso traz o rotulo e o valor dos dois lados da comparacao. // O objetivo e ver, lado a lado, o que == e === respondem. $casos = [ ['17', 17, '"17"', '17'], ['17', 17, '17', 17], ['0', 0, '""', ''], ['0', 0, 'null', null], ['0', 0, 'false', false], ['"0"', '0', '""', ''], ['"0"', '0', 'false', false], ['1', 1, 'true', true], ['"abc"', 'abc', '0', 0], ['1.0', 1.0, 'true', true], ['"1"', '1', 'true', true], ['0.0', 0.0, 'null', null], ]; printf("%-8s %-9s %-9s %-6s %-6s\n", 'A', 'B', '', '==', '==='); foreach ($casos as [$rotA, $a, $rotB, $b]) { printf( "%-8s %-9s %-9s %-6s %-6s\n", $rotA, $rotB, gettype($a) . '/' . gettype($b), var_export($a == $b, true), var_export($a === $b, true) ); } // != e o mesmo que == negado; !== nega o ===. // <> e apelido antigo de != e nao deve ser usado em codigo novo. echo "\nNegacoes com os mesmos pares\n"; $pares = [[17, '17'], [0, ''], [0, null], [0, false], ['0', false]]; foreach ($pares as [$a, $b]) { printf( " %-6s vs %-7s !=: %-6s !==: %-6s <>: %s\n", var_export($a, true), var_export($b, true), var_export($a != $b, true), var_export($a !== $b, true), var_export($a <> $b, true) ); } // A falha mais comum: validar dado que veio do formulario com ==. // O texto "0" passa na validacao de "nao preencha o campo". echo "\nValidacao de formulario feita com ==\n"; $cep = '0'; // o usuario digitou zero no campo if ($cep == '') { echo ' resultado: campo obrigatorio em branco (o "0" passou como preenchido)' . "\n"; } $cep = '01310-100'; if ($cep == '') { echo ' resultado: campo obrigatorio em branco' . "\n"; } else { echo ' resultado: CEP ' . $cep . ' aceito' . "\n"; } // A versao com === trata o "0" como preenchimento tambem, mas o teste correto // aqui e emptiness explicito, e nao comparacao com string vazia. echo "\nComo tratar isso de verdade\n"; $campos = ['nome' => '', 'email' => '[email protected]', 'obs' => '0']; foreach ($campos as $campo => $valor) { $vazio = !isset($valor) || trim($valor) === ''; printf(" %-6s valor %-24s em branco: %s\n", $campo, var_export($valor, true), var_export($vazio, true)); } // Comparacao estrita entre tipos diferentes e sempre falsa, sem excecao. echo "\nTipos diferentes nunca passam no ===\n"; $misturados = [[1, 1.0], [1, '1'], [0, false], [0, null], [null, ''], [[], false]]; foreach ($misturados as [$a, $b]) { printf( " %-8s vs %-8s ==: %-6s ===: %s\n", var_export($a, true), var_export($b, true), var_export($a == $b, true), var_export($a === $b, true) ); }
Saída real
A B == === 17 "17" integer/string true false 17 17 integer/integer true true 0 "" integer/string false false 0 null integer/NULL true false 0 false integer/boolean true false "0" "" string/string false false "0" false string/boolean true false 1 true integer/boolean true false "abc" 0 string/integer false false 1.0 true double/boolean true false "1" true string/boolean true false 0.0 null double/NULL true false Negacoes com os mesmos pares 17 vs '17' !=: false !==: true <>: false 0 vs '' !=: true !==: true <>: true 0 vs NULL !=: false !==: true <>: false 0 vs false !=: false !==: true <>: false '0' vs false !=: false !==: true <>: false Validacao de formulario feita com == resultado: CEP 01310-100 aceito Como tratar isso de verdade nome valor '' em branco: true email valor '[email protected]' em branco: false obs valor '0' em branco: false Tipos diferentes nunca passam no === 1 vs 1.0 ==: true ===: false 1 vs '1' ==: true ===: false 0 vs false ==: true ===: false 0 vs NULL ==: true ===: false NULL vs '' ==: true ===: false array ( ) vs false ==: true ===: false