Dia 3 — Estruturas de controle: PHP e MySQL

Informatica · Conteudo · publicado em 02/10/2026
Dia 3 de 17

Estruturas de controle

Aula 1

if, elseif e else

if, elseif e else

O if executa um bloco quando a condição e verdadeira. O elseif testa uma condição alternativa quando a anterior falhou, e o else cobre o resto. Assim que uma condição passa, as seguintes nem são avaliadas.

Sintaxe

if ($nota >= 9) {
    $conceito = 'A';
} elseif ($nota >= 7) {
    $conceito = 'B';
} elseif ($nota >= 5) {
    $conceito = 'C';
} else {
    $conceito = 'D';
}

elseif e uma palavra so. else if com espaco e sintaxe invalida e causa erro de compilacao.

A ordem das condições importa: a primeira que passar vence. Em uma tabela de notas, vao da mais restritiva para a mais solta — se o primeiro if fosse $nota >= 5, os outros nunca seriam alcancados.

Escopo e o return antecipado

O if não cria escopo. Uma variável declarada dentro do bloco continua existindo depois dele, e uma variável usada dentro pode nem existir — o aviso "undefined variable" vem dai.

Para não acumular varios niveis de aninhamento, use o return antecipado: cada condição que falha sai da função na hora, e o código valido continua no nivel principal.

function validarIdade(int $idade): string
{
    if ($idade < 0) {
        return 'idade invalida';
    }

    if ($idade < 16) {
        return 'bloqueado';
    }

    return 'liberado';
}

Condições compostas e a sintaxe alternativa

Com && e || cabem varias regras no mesmo if. Quando houver negacao, o parenteses evita a leitura errada: !($nota >= 7 && $fezTrabalho) nega o conjunto inteiro, e não so a primeira parte.

Para misturar PHP com HTML em uma página, existe a sintaxe com dois pontos e endif, que dispensa as chaves:

<?php if ($mensagem !== ''): ?>
  <p><?= htmlspecialchars($mensagem, ENT_QUOTES, 'UTF-8') ?></p>
<?php else: ?>
  <p>Sem mensagem.</p>
<?php endif; ?>

O <?= ?> e o atalho de <?php echo ?>. Nos dois casos, : substitui o { inicial e endif; substitui o } final.

Exemplo

<?php
declare(strict_types=1);

//-if classico: uma condicao, dois caminhos.
$nota = 7.5;

if ($nota >= 7) {
    echo "1. nota $nota: aprovado\n";
} else {
    echo "1. nota $nota: reprovado\n";
}

//-if com elseif: a primeira condicao verdadeira ganha e as outras sao
// ignoradas, porque elseif e else-if nao sao blocos independentes.
$situacao = '';
if ($nota >= 9) {
    $situacao = 'A';
} elseif ($nota >= 7) {
    $situacao = 'B';
} elseif ($nota >= 5) {
    $situacao = 'C';
} else {
    $situacao = 'D';
}
echo "2. nota $nota caiu em $situacao\n";

// A ordem das condicoes importa: se a primeira for mais frouxa, as outras
// nunca vao ser testadas.
$idade = 12;
if ($idade > 0) {
    echo "3. teste1: idade maior que zero\n";
} elseif ($idade > 10) {
    echo "3. teste2: idade maior que dez\n";
} else {
    echo "3. nenhum teste passou\n";
}

// && e || dentro do if: use parenteses quando houver negacao.
$nota = 6.0;
$fezTrabalho = true;
if ($nota >= 6.0 && $fezTrabalho) {
    echo "4. nota minima e trabalho entregue: aprovado\n";
}

if (!($nota >= 7.0 && $fezTrabalho)) {
    echo "5. com parenteses: !(nota >= 7 E trabalho) = " . "verdadeiro, bloco executado\n";
}

// Escopo: a variavel criada dentro do if existe fora dele, porque o PHP nao
// tem bloco de escopo para if.
if (true) {
    $criadaDentro = 'ok';
}
echo '6. variavel criada dentro do if: ' . ($criadaDentro ?? 'nao existe') . "\n";

// Return antecipado: sai da funcao assim que a condicao falha, em vez de
// aninhar o resto do codigo em varios else.
function validarIdade(int $idade): string
{
    if ($idade < 0) {
        return 'idade invalida';
    }

    if ($idade < 16) {
        return 'bloqueado: menor de 16';
    }

    return 'liberado';
}

echo '7. validarIdade(14) -> ' . validarIdade(14) . "\n";
echo '   validarIdade(17) -> ' . validarIdade(17) . "\n";
echo '   validarIdade(-1) -> ' . validarIdade(-1) . "\n";

// elseif nao aceita else if separado: else if e sintaxe invalida.
echo "\n8. elseif e uma unica palavra\n";

// Sintaxe alternativa com dois pontos e endif: usada em paginas que
// misturam PHP com HTML.
$mensagem = 'Bem-vindo';
?>
<div class="caixa">
<?php if ($mensagem !== ''): ?>
  <p><?= htmlspecialchars($mensagem, ENT_QUOTES, 'UTF-8') ?></p>
<?php else: ?>
  <p>Sem mensagem.</p>
<?php endif; ?>
</div>
<?php
echo "9. bloco HTML acima foi gerado com if(): endif;\n";

Saída real

1. nota 7.5: aprovado
2. nota 7.5 caiu em B
3. teste1: idade maior que zero
4. nota minima e trabalho entregue: aprovado
5. com parenteses: !(nota >= 7 E trabalho) = verdadeiro, bloco executado
6. variavel criada dentro do if: ok
7. validarIdade(14) -> bloqueado: menor de 16
   validarIdade(17) -> liberado
   validarIdade(-1) -> idade invalida

8. elseif e uma unica palavra
<div class="caixa">
  <p>Bem-vindo</p>
</div>
9. bloco HTML acima foi gerado com if(): endif;
Aula 2

Operador ternário e coalescência

Operador ternário e coalescência

O ternario e uma expressao: ele devolve um valor e pode ser usado onde um valor for esperado, inclusive dentro de outra expressao. O ?? devolve um valor padrao quando o da esquerda e null ou não existe.

O ternario

$situacao = $nota >= 7 ? 'aprovado' : 'reprovado';
echo $nota >= 7 ? 'aprovado' : 'reprovado';

Os dois ramos precisam devolver o mesmo tipo — um int e uma string no mesmo ternario funcionam, mas o resultado vira string. Para deixar a regra sem ambiguidade: um ternario não substitui um if com bloco grande. Ele serve para uma escolha de um valor; quando ha varias linhas em cada caminho, o if fica mais legivel.

Ternarios aninhados são legiveis em um nivel, mas com mais de três niveis a leitura se perde:

$situacao = $nota >= 7 ? 'aprovado' : ($nota >= 5 ? 'recuperacao' : 'reprovado');

O operador Elvis e o ternario sem valor no lado esquerdo:

$nickname ?: $nome;

Quando $nickname for verdadeiro, devolve $nickname; senao devolve $nome. O detalhe importante: a condição e a veracidade do valor, e não se ele existe. Zero e a string "0" são falsos, então um campo preenchido com "0" e substituido mesmo assim.

?? e ??=

O ?? age so sobre null e sobre variável inexistente:

Valor?? 'padrao'
null'padrao'
inexistente'padrao'
00
'0''0'
''''
falsefalse

Essa e a diferença entre o Elvis e o coalescente: ?: trata 0, "0", "" e false como ausente; ?? trata apenas null.

O ??= e a versão que atribui:

$cidade ??= 'Recife';   // so atribui se $cidade for null ou nao existir

Com $quantidade = 0, o ??= não atribui, porque zero não e null.

Encurtamento de isset

$a ?? $b e exatamente isset($a) ? $a : $b, sem avaliar $a duas vezes. E o padrao para ler dado de formulario ou de array:

$pagina  = $_GET['pagina'] ?? 1;
$nome    = $usuario['apelido'] ?? $usuario['nome'] ?? 'Visitante';
$quantidade = $_GET['qtd'] ?? 1;

A cadeia de ?? e avaliada da esquerda para a direita e para no primeiro valor que existir, então $usuario['apelido'] so e lido se $usuario existir. O operador ?: tem o mesmo encurtamento para expressao, sem a parte de atribuição.

Exemplo

<?php
declare(strict_types=1);

// O ternario e uma expressao: vale onde um valor for esperado.
$idade = 17;
$maiorDeDezoito = $idade >= 18;

echo "1. Ternario com valor nos dois ramos\n";
echo '   $idade >= 18 ? "maior" : "menor"  -> ' . ($idade >= 18 ? 'maior' : 'menor') . "\n";
echo '   $resultado                          -> ' . ($maiorDeDezoito ? 'liberado' : 'bloqueado') . "\n";

$desconto = 500;
$total = 1000;
echo '   500 >= 500 ? ...                   -> ' . ($desconto >= 500 ? 'cupom aplicado' : 'cupom minimo nao atingido') . "\n";

// ?: sem o valor da esquerda devolve o proprio valor quando a condicao e
// falsa. E o chamado "operador Elvis". So vale quando o padrao e a variavel.
$nickname = '';
$nome = 'Maria';
echo "\n2. Operador elvis ?: com a variavel dos dois lados\n";
echo '   $nickname ?: $nome  -> ' . ($nickname ?: $nome) . "\n";

$nickname = 'mari';
echo '   $nickname ?: $nome  -> ' . ($nickname ?: $nome) . "\n";

// Atencao: quando o valor da esquerda e 0 ou "0", o elvis troca mesmo
//que a variavel esteja preenchida.
$quantidade = 0;
$padrao = 1;
echo '   $quantidade ?: $padrao -> ' . ($quantidade ?: $padrao) . " (0 e falso em contexto booleano)\n";

// ?? so troca quando o valor e null ou nao existe. Zero e string vazia
// passam intactos.
echo "\n3. ?? (coalescente) so age sobre null\n";
$campo = '0';
var_dump($campo ?? 'padrao');
var_dump(isset($campo), isset($campoVazio));
var_dump($campoVazio ?? 'padrao');
var_dump(null ?? 'padrao');

$nulo = null;
echo '   $nulo ?? "padrao" -> ' . ($nulo ?? 'padrao') . "\n";
echo '   $nulo ?: "padrao" -> ' . ($nulo ?: 'padrao') . "\n";

// ?: sobre o resultado de uma funcao e o atalho de isset() com encurtamento.
echo "\n4. Encurtamento de isset()\n";
$total = $_GET['total'] ?? 0;
echo '   $_GET["total"] ?? 0 -> ' . var_export($total, true) . "\n";
$total = $_GET['total'] ?? 0;
echo '   com valor no $_GET   -> ' . var_export($_GET['total'] ?? 0, true) . "\n";

// ??= atribui o padrao somente quando a variavel e null ou nao existe.
echo "\n5. ??= atribuicao coalescente\n";
$cidade = '';
$cidade ??= 'Recife';
echo '   depois de ??=       -> ' . var_export($cidade, true) . "\n";

$cidade = 'Olinda';
$cidade ??= 'Recife';
echo '   se ja tinha valor    -> ' . var_export($cidade, true) . "\n";

$contador = 0;
$contador ??= 10;
echo '   zero nao e null      -> ' . $contador . "\n";

// Combinando os tres: forma curta de um if/else que so atribui valores.
echo "\n6. Padrao de uso: atribuir com fallback\n";
$quantidade = $_GET['qtd'] ?? null;
$quantidade = $quantidade > 0 ? $quantidade : 1;
echo '   quantidade normalizada -> ' . $quantidade . "\n";

$pagina = $_GET['pagina'] ?? 1;
echo '   pagina padrao          -> ' . $pagina . "\n";

$nomeExibido = $usuario['apelido'] ?? $usuario['nome'] ?? 'Visitante';
echo '   cadeia de ??           -> ' . $nomeExibido . "\n";

Saída real

1. Ternario com valor nos dois ramos
   $idade >= 18 ? "maior" : "menor"  -> menor
   $resultado                          -> bloqueado
   500 >= 500 ? ...                   -> cupom aplicado

2. Operador elvis ?: com a variavel dos dois lados
   $nickname ?: $nome  -> Maria
   $nickname ?: $nome  -> mari
   $quantidade ?: $padrao -> 1 (0 e falso em contexto booleano)

3. ?? (coalescente) so age sobre null
string(1) "0"
bool(true)
bool(false)
string(6) "padrao"
string(6) "padrao"
   $nulo ?? "padrao" -> padrao
   $nulo ?: "padrao" -> padrao

4. Encurtamento de isset()
   $_GET["total"] ?? 0 -> 0
   com valor no $_GET   -> 0

5. ??= atribuicao coalescente
   depois de ??=       -> ''
   se ja tinha valor    -> 'Olinda'
   zero nao e null      -> 0

6. Padrao de uso: atribuir com fallback
   quantidade normalizada -> 1
   pagina padrao          -> 1
   cadeia de ??           -> Visitante
Aula 3

match e switch

match e switch

Os dois escolhem entre valores, mas não são equivalentes. O switch e uma estrutura de controle que compara com ==; o match e uma expressao que compara com === e devolve um valor.

match

$estado = match ($sigla) {
    'SP' => 'Sao Paulo',
    'RJ' => 'Rio de Janeiro',
    'MG' => 'Minas Gerais',
    default => 'Estado nao cadastrado',
};

Como e expressao, o resultado pode ser atribuido, passado como argumento ou impresso direto:

echo match ($opcao) { 'a' => 1, 'b' => 2, default => 0 };

Pontos que mudam em relacao ao switch:

  • Compara com ===, então 1 não casa com '1'.
  • Cada caso e testado e so um executa. Não existe queda entre casos, e o break e obrigatorio na sintaxe.
  • Varios valores podem cair no mesmo bloco, separados por virgula: $dia === 'sabado', $dia === 'domingo' => 'fim de semana'.
  • O default e obrigatorio. Sem ele, a expressao fica indefinida e usar o resultado gera Error: Undefined array key ou erro grave.

O par de match(true) traz a lógica de condições sem if aninhado:

$situacao = match (true) {
    $nota >= 7.0 => 'aprovado',
    $nota >= 5.0 && $fezRecuperacao => 'aprovado em recuperacao',
    default => 'reprovado',
};

switch

O switch compara com ==, e por isso aceita tipos diferentes: case '1': casa com o número 1. A comparacao também passa o valor por string, então case 8.4: casa com '8.4'.

switch ($nivel) {
    case 1:
        echo 'nivel 1';
        break;
    case 2:
        echo 'nivel 2';
        break;
    default:
        echo 'nivel nao mapeado';
}

O break e obrigatorio para o caso parar ai. Sem ele, o switch continua caindo no proximo caso — o chamado *fallthrough* — e imprime o caso 1, o caso 2 e o caso 3.

Qual usar

SituacaoEscolha
Devolver um valor para uma variável ou argumentomatch
Comparar tipos diferentes sem se preocuparswitch
Varias condições logicas em vez de valoresmatch (true)
Agrupar valores que levam ao mesmo resultadomatch com virgula

O switch aceita case e default em qualquer posicao e não aceita expressao como valor de case. O match exige que os valores sejam constantes ou expressoes validas, e não aceita case nem break.

Exemplo

<?php
declare(strict_types=1);

// match e uma expressao: devolve um valor, como uma variavel ou um argumento.
$sigla = 'MG';
$estado = match ($sigla) {
    'SP' => 'Sao Paulo',
    'RJ' => 'Rio de Janeiro',
    'MG' => 'Minas Gerais',
    default => 'Estado nao cadastrado',
};
echo "1. match como expressao\n";
echo "   match('MG')      -> $estado\n";

// Varios casos podem cair no mesmo bloco, separados por virgula.
$dia = 'sabado';
$tipo = match (true) {
    $dia === 'sabado', $dia === 'domingo' => 'fim de semana',
    default => 'dia util',
};
echo "\n2. Varios casos no mesmo bloco, separados por virgula\n";
echo "   $dia             -> $tipo\n";

// Sem default a expressao fica indefinida eipo erro grave ao ser usada.
$opcao = 'x';
echo "\n3. Sem default a expressao fica indefinida\n";
// $r = match ($opcao) { 'a' => 1 };   // descomente para ver o erro

$resultado = match ($opcao) {
    'a' => 1,
    'b' => 2,
    default => 0,
};
echo "   com default      -> $resultado\n";

// switch compara com ==. Por isso 1 casa com '1'.
echo "\n4. switch usa == e por isso aceita tipos diferentes\n";
$valor = 1;
switch ($valor) {
    case '1':
        echo "   switch: casou com '1' (texto)\n";
        break;
    case 1:
        echo "   switch: casou com 1 (numero)\n";
        break;
}
echo "   ou seja, o case '1' foi escolhido antes do case 1\n";

$numero = 1;
$resultadoSwitch = match ($numero) {
    '1' => 'texto um',
    1 => 'numero um',
    default => 'nenhum',
};
echo "   match com os mesmos casos -> $resultadoSwitch\n";

// Sem break, o switch cai no proximo caso (fallthrough).
echo "\n5. Sem break o switch continua caindo nos proximos casos\n";
$nivel = 2;
switch ($nivel) {
    case 1:
        echo "   nivel 1\n";
    case 2:
        echo "   nivel 2\n";
    case 3:
        echo "   nivel 3\n";
        break;
    case 4:
        echo "   nivel 4\n";
}
echo "   (o nivel 3 tambem apareceu: faltou break no caso 2)\n";

// break so do case 3 em diante impede a queda.
echo "\n6. Com break em todos os casos\n";
switch ($nivel) {
    case 1:
        echo "   nivel 1\n";
        break;
    case 2:
        echo "   nivel 2\n";
        break;
    case 3:
        echo "   nivel 3\n";
        break;
    default:
        echo "   nivel nao mapeado\n";
}

// Em switch o valor e convertido para string na comparacao com case.
echo "\n7. Casos com numeros decimais em switch\n";
$nota = '8.4';
switch ($nota) {
    case 8.4:
        echo "   '8.4' casou com 8.4 (numeros viram string na comparacao)\n";
        break;
    default:
        echo "   nenhum caso casou\n";
}

// O par IGUAL de switch e match(true), que traz a logica de condicoes.
echo "\n8. Substituir cadeia de if por match(true)\n";
$nota = 5.5;
$fezRecuperacao = true;
$situacao = match (true) {
    $nota >= 7.0 => 'aprovado',
    $nota >= 5.0 && $fezRecuperacao => 'aprovado em recuperacao',
    default => 'reprovado',
};
echo "   nota $nota -> $situacao\n";

// Comparacao entre varios valores, util para calculos.
echo "\n9. Calculando com match\n";
$operacao = 'divisao';
$a = 12;
$b = 4;
$r = match ($operacao) {
    'soma' => $a + $b,
    'subtracao' => $a - $b,
    'multiplicacao' => $a * $b,
    'divisao' => $b !== 0 ? intdiv($a, $b) : 'divisao por zero',
    'resto' => $a % $b,
    default => 'operacao desconhecida',
};
echo "   $operacao($a, $b) -> $r\n";

Saída real

1. match como expressao
   match('MG')      -> Minas Gerais

2. Varios casos no mesmo bloco, separados por virgula
   sabado             -> fim de semana

3. Sem default a expressao fica indefinida
   com default      -> 0

4. switch usa == e por isso aceita tipos diferentes
   switch: casou com '1' (texto)
   ou seja, o case '1' foi escolhido antes do case 1
   match com os mesmos casos -> numero um

5. Sem break o switch continua caindo nos proximos casos
   nivel 2
   nivel 3
   (o nivel 3 tambem apareceu: faltou break no caso 2)

6. Com break em todos os casos
   nivel 2

7. Casos com numeros decimais em switch
   '8.4' casou com 8.4 (numeros viram string na comparacao)

8. Substituir cadeia de if por match(true)
   nota 5.5 -> aprovado em recuperacao

9. Calculando com match
   divisao(12, 4) -> 3
Aula 4

Valores verdadeiros e falsos

Valores verdadeiros e falsos

Quando um valor aparece numa condição, o PHP o converte para bool. A conversao e quase sempre intuitiva, com duas excecoes que quebram validacao de formulario: a string "0" e o array vazio são falsos.

Os unicos valores falsos

ValorConvertido
falsefalso
0falso
0.0falso
''falso
'0'falso
[]falso
nullfalso
qualquer outro valorverdadeiro

'0.0', ' ' (espaco), 'false' e 'off' são verdadeiros: são strings não vazias, e string não vazia e sempre verdadeira. O que decide e o conteudo, não o que o texto parece significar.

O array com um zero dentro e verdadeiro: [0] passa na condição, porque o array tem um elemento.

empty, isset e is_null

FunçãoVerdadeiro quando
empty($x)false, 0, 0.0, '', '0', [], null ou variável ausente
isset($x)a variável existe e não e null
is_null($x)o valor e exatamente null

isset() e empty() não são o oposto um do outro: um array vazio faz empty() verdadeiro e isset() verdadeiro ao mesmo tempo. E isset() responde duas perguntas — existe e não e null — o que costuma ser exatamente o que se quer checar.

$vazio = !isset($valor) || trim($valor) === '';

Esse e o teste correto para campo obrigatorio: o !isset() cobre a variável ausente e o null, e o trim() === '' cobre a string em branco sem confundir o "0".

Precedencia do !

O ! tem prioridade sobre ==, então a negacao precisa de parenteses quando o alvo e a comparacao:

!$a == true;      // e (! $a) == true
!($a == true);    // nega a comparacao inteira

Para tornar a intencao visivel, o casting explicito ajuda: (bool) '0' devolve false e mostra na cara que a conversao e o ponto.

Imprimir o booleano com echo mostra 1 ou vazio; o var_dump() mostra bool(true) ou bool(false), e o var_export($x, true) devolve 'true' ou 'false' como texto.

Exemplo

<?php
declare(strict_types=1);

// Todo valor e convertido para booleano quando aparece numa condicao.
// Estes sao os unicos valores falsos do PHP.
$falsos = [
    'false'      => false,
    'int 0'      => 0,
    'float 0.0'  => 0.0,
    'string ""'  => '',
    'string "0"' => '0',
    'array []'   => [],
];

echo "1. Os valores falsos do PHP\n";
foreach ($falsos as $rotulo => $valor) {
    printf("   %-12s em if: %s\n", $rotulo, $valor ? 'executa' : 'nao executa');
}

// string "0" e falsa; qualquer outra string e verdadeira, mesmo "0.0" ou " ".
echo "\n2. O que acontece com outras strings\n";
foreach (['0', '0.0', ' ', 'false', 'off', 'nao'] as $s) {
    printf("   %-8s -> %s\n", var_export($s, true), $s ? 'verdadeira' : 'falsa');
}

// O array vazio e falso. Array com um zero dentro e verdadeiro.
echo "\n3. Array vazio e falso\n";
var_dump([] ? 'verdadeiro' : 'falso', [0] ? 'verdadeiro' : 'falso', [''] ? 'verdadeiro' : 'falso');

// Funcoes que checam valor vazio.
echo "\n4. empty() e isset()\n";
$nulo = null;
$zero = 0;
$vazio = '';
$texto = '0';
var_dump(empty($nulo), empty($zero), empty($vazio), empty($texto), empty('abc'));
var_dump(empty([]), empty([0]));

// isset() responde se a variavel existe e nao e null.
var_dump(isset($naoExiste), isset($nulo), isset($zero), isset($vazio), isset($texto));

// is_null() so responde sobre null.
var_dump(is_null($nulo), is_null($zero), is_null($vazio));

// A combinacao classica de validacao.
echo "\n5. isset() e vazio juntos na validacao\n";
$cep = '0';
var_dump(isset($cep) && trim($cep) !== '');
$cep = '';
var_dump(isset($cep) && trim($cep) !== '');
$cep = null;
var_dump(isset($cep) && trim($cep) !== '');

// O operador negacao em expressao: cuidado com a precedencia de ! e ==.
echo "\n6. Cuidado: ! tem precedencia sobre ==\n";
$a = 0;
var_dump(!$a == true);
var_dump(!($a == true));
var_dump(!$a === true);

// Cast explicito para booleano.
echo "\n7. (bool) deixa a intencao explicita\n";
var_dump((bool) '0', (bool) 1, (bool) [], (bool) null, (bool) ' ');

// Booleano impresso vira string no echo.
echo "\n8. Como o booleano aparece impresso\n";
var_dump(true, false);
echo '   echo de true  -> ' . var_export(true, true) . "\n";
echo '   echo de false -> ' . var_export(false, true) . "\n";
echo '   em string: "valor: " . true  -> ' . ('valor: ' . var_export(true, true)) . "\n";

// empty() em string interpolada precisa de parênteses para nao virar parse error.
echo "\n9. empty() dentro de aspas duplas\n";
$m = '';
echo '   $m = ""    -> ' . (empty($m) ? 'vazio' : 'com conteudo') . "\n";
$m = '0';
echo '   $m = "0"   -> ' . (empty($m) ? 'vazio' : 'com conteudo') . "\n";
$m = '0.0';
echo '   $m = "0.0" -> ' . (empty($m) ? 'vazio' : 'com conteudo') . "\n";

Saída real

1. Os valores falsos do PHP
   false        em if: nao executa
   int 0        em if: nao executa
   float 0.0    em if: nao executa
   string ""    em if: nao executa
   string "0"   em if: nao executa
   array []     em if: nao executa

2. O que acontece com outras strings
   '0'      -> falsa
   '0.0'    -> verdadeira
   ' '      -> verdadeira
   'false'  -> verdadeira
   'off'    -> verdadeira
   'nao'    -> verdadeira

3. Array vazio e falso
string(5) "falso"
string(10) "verdadeiro"
string(10) "verdadeiro"

4. empty() e isset()
bool(true)
bool(true)
bool(true)
bool(true)
bool(false)
bool(true)
bool(false)
bool(false)
bool(false)
bool(true)
bool(true)
bool(true)
bool(true)
bool(false)
bool(false)

5. isset() e vazio juntos na validacao
bool(true)
bool(false)
bool(false)

6. Cuidado: ! tem precedencia sobre ==
bool(true)
bool(true)
bool(true)

7. (bool) deixa a intencao explicita
bool(false)
bool(true)
bool(false)
bool(false)
bool(true)

8. Como o booleano aparece impresso
bool(true)
bool(false)
   echo de true  -> true
   echo de false -> false
   em string: "valor: " . true  -> valor: true

9. empty() dentro de aspas duplas
   $m = ""    -> vazio
   $m = "0"   -> vazio
   $m = "0.0" -> com conteudo