Skip to content

4. Exercício prático - IMPOTS

4.1. O problema

Propõe-se escrever um programa que permita calcular o imposto de um contribuinte. Consideramos o caso simplificado de um contribuinte que tenha apenas seu salário para declarar:

  • calcula-se o número de cotas do funcionário nbParts = nbEnfants/2 + 1 se ele for solteiro, nbEnfants/2 + 2 se ele for casado, onde nbEnfants é o número de filhos dele.
  • calcula-se sua renda tributável R = 0,72 * S, onde S é seu salário anual
  • calcula-se seu coeficiente familiar Q = R/N

calcula-se seu imposto I com base nos seguintes dados

12620,0
0
0
13.190
0,05
631
15.640
0,1
1.290,5
24.740
0,15
2.072,5
31.810
0,2
3.309,5
39.970
0,25
4.900
48.360
0,3
6.898,5
55.790
0,35
9.316,5
92.970
0,4
12.106
127.860
0,45
16.754,5
151.250
0,50
23.147,5
172.040
0,55
30.710
195.000
0,60
39.312
0
0,65
49.062

Cada linha possui 3 campos. Para calcular o imposto I, procura-se a primeira linha em que QF ≤ campo1. Por exemplo, se QF = 30000, será encontrada a linha

    24740        0.15        2072.5

O imposto I é, então, igual a 0,15*R - 2072,5*nbParts. Se QF for tal que a relação QF <= campo1 nunca for verificada, então serão utilizados os coeficientes da última linha. Aqui:

    0                0.65        49062

o que resulta no imposto I = 0,65 * R – 49.062 * nbParts.

4.2. Versão com tabelas (impots_01)

Apresentamos um primeiro programa em que:

  • os dados necessários para o cálculo do imposto estão em três tabelas (limites, coeffR, coeffN)
  • os dados dos contribuintes (casado, filhos, salário) estão em um primeiro arquivo de texto
  • os resultados do cálculo do imposto (estado civil, filhos, salário, imposto) são armazenados em um segundo arquivo de texto

<?php

// definição das constantes
$DATA = "data.txt";
$RESULTATS = "resultats.txt";
$limites = array(12620, 13190, 15640, 24740, 31810, 39970, 48360, 55790, 92970, 127860, 151250, 172040, 195000);
$coeffR = array(0, 0.05, 0.1, 0.15, 0.2, 0.25, 0.3, 0.35, 0.4, 0.45, 0.5, 0.55, 0.6, 0.65);
$coeffN = array(0, 631, 1290.5, 2072.5, 3309.5, 4900, 6898.5, 9316.5, 12106, 16754.5, 23147.5, 30710, 39312, 49062);

// leitura dos dados
$data = fopen($DATA, "r");
if (!$data) {
  print "Impossible d'ouvrir en lecture le fichier des données [$DATA]\n";
  exit;
}

// abertura do arquivo de resultados
$résultats = fopen($RESULTATS, "w");
if (!$résultats) {
  print "Impossible de créer le fichier des résultats [$RESULTATS]\n";
  exit;
}

// processa-se a linha atual do arquivo de dados
while ($ligne = fgets($data, 100)) {
  // remove-se o eventual caractere de fim de linha
  $ligne = cutNewLineChar($ligne);
  // recuperam-se os três campos “casado”, “filhos” e “salário” que formam $ligne
  list($marié, $enfants, $salaire) = explode(",", $ligne);
  // calcula-se o imposto
  $impôt = calculImpots($marié, $enfants, $salaire, $limites, $coeffR, $coeffN);
  // insere-se o resultado no arquivo de resultados
  fputs($résultats, "$marié:$enfants:$salaire:$impôt\n");
  // próximo contribuinte
}
// fecha-se os arquivos
fclose($data);
fclose($résultats);

// fim
exit;

// --------------------------------------------------------------------------
function cutNewLinechar($ligne) {
  // elimina-se o marcador de fim de linha de $ligne, se houver
  $L = strlen($ligne);  // comprimento da linha
  while (substr($ligne, $L - 1, 1) == "\n" or substr($ligne, $L - 1, 1) == "\r") {
    $ligne = substr($ligne, 0, $L - 1);
    $L--;
  }
  // fim
  return($ligne);
}

// --------------------------------------------------------------------------
function calculImpots($marié, $enfants, $salaire, $limites, $coeffR, $coeffN) {
  // $marié: sim, não
  // $enfants: número de filhos
  // $salaire: salário anual
  // $limites, $coeffR, $coeffN: tabelas de dados que permitem o cálculo do imposto
  
  // número de cotas
  $marié = strtolower($marié);
  if ($marié == "oui")
    $nbParts = $enfants / 2 + 2;
  else
    $nbParts=$enfants / 2 + 1;
  // mais 1/2 parcela se houver pelo menos 3 filhos
  if ($enfants >= 3)
    $nbParts+=0.5;
  // renda tributável
  $revenuImposable = 0.72 * $salaire;
  // quociente familiar
  $quotient = $revenuImposable / $nbParts;
  // é inserido no final da tabela de limites para encerrar o ciclo a seguir
  array_push($limites, $quotient);
  // cálculo do imposto
  $i = 0;
  while ($quotient > $limites[$i])
    $i++;
  // como colocamos $quotient no final da tabela $limites, o loop anterior
  // não pode ultrapassar os limites da tabela $limites
  // agora podemos calcular o imposto
  return floor($revenuImposable * $coeffR[$i] - $nbParts * $coeffN[$i]);
}
?>

O arquivo de dados data.txt (casado, filhos, salário):

oui,2,200000
non,2,200000
oui,3,200000
non,3,200000
oui,5,50000
non,0,3000000

Os arquivos résultats.txt (estado civil, filhos, salário, imposto) dos resultados obtidos:

oui:2:200000:22504
non:2:200000:33388
oui:3:200000:16400
non:3:200000:22504
oui:5:50000:0
non:0:3000000:1354938

Comentários

  • linha 4: o nome do arquivo de texto que contém os dados dos contribuintes (estado civil, filhos, salário)
  • linha 5: o nome do arquivo de texto que contém os resultados (estado civil, filhos, salário, imposto) do cálculo do imposto
  • linhas 6-8: as três tabelas de dados que permitem o cálculo do imposto
  • linhas 11-15: abertura do arquivo de dados dos contribuintes para leitura
  • linhas 18-22: abertura do arquivo de resultados para gravação
  • linha 25: loop de leitura das linhas (casado, filhos, salário) do arquivo dos contribuintes
  • linha 27: o marcador de fim de linha é removido
  • linha 29: os componentes (casado, filhos, salário) da linha são recuperados
  • linha 31: o imposto é calculado
  • linha 33: o imposto é gravado no arquivo de resultados
  • linhas 37-38: uma vez que o arquivo dos contribuintes foi totalmente processado, os arquivos são fechados
  • linha 44: a função que remove o caractere de fim de linha de uma linha $ligne. O caractere de fim de linha é a sequência “\r\n” em sistemas Windows e “\n” em sistemas Unix. O resultado é a sequência de entrada sem o caractere de fim de linha.
  • linhas 47-48: substr($chaîne,$début,$taille) é a subcadeia de $chaîne que começa no caractere $début e tem, no máximo, $taille caracteres.
  • linha 63: strtolower($chaîne) transforma $chaîne em letras minúsculas
  • linha 76: array_push($tableau,$élément) adiciona $élément ao final da matriz $tableau. Observe-se que a matriz $limites foi passada por valor para a função calculerImpot (linha 56: )). Essa adição de elemento é feita, portanto, na cópia do parâmetro efetivo, que permanece inalterado.
  • linha 84: a função floor($x) retorna o valor inteiro imediatamente inferior a $x.

4.3. Versão com arquivos de texto (impots_02)

Esta nova versão difere da anterior apenas pelo fato de que os dados ($limites, $coeffR, $coeffN) necessários para o cálculo do imposto estão agora em um arquivo de texto no seguinte formato:

Arquivo impots.txt:

12620:13190:15640:24740:31810:39970:48360:55790:92970:127860:151250:172040:195000:0
0:0.05:0.1:0.15:0.2:0.25:0.3:0.35:0.4:0.45:0.5:0.55:0.6:0.65
0:631:1290.5:2072.5:3309.5:4900:6898.5:9316.5:12106:16754.5:23147.5:30710:39312:49062

A nova versão limita-se a ler os dados do arquivo [impots.txt] para inseri-los em três tabelas ($limites, $coeffR, $coeffN). Assim, voltamos ao caso anterior. Apresentamos apenas as alterações:


<?php

// definição das constantes
$DATA = "data.txt";
$RESULTATS = "resultats.txt";
$IMPOTS = "impots.txt";

// os dados necessários para o cálculo do imposto foram inseridos no arquivo $IMPOTS
// com uma linha por tabela, no formato
// val1:val2:val3,...
list($erreur, $limites, $coeffR, $coeffN) = getTables($IMPOTS);

// houve algum erro?
if ($erreur) {
  print "$erreur\n";
  exit;
}//if
// leitura dos dados do usuário
...

// fim
exit;

// --------------------------------------------------------------------------
function cutNewLinechar($ligne) {
  // a marca de fim de linha de $ligne é removida, se existir
...
}

// --------------------------------------------------------------------------
function calculImpots($marié, $enfants, $salaire, $limites, $coeffR, $coeffN) {
  // $marié: sim, não
  // $enfants: número de filhos
  // $salaire: salário anual
  // $limites, $coeffR, $coeffN: tabelas de dados que permitem o cálculo do imposto
  ...
}

// --------------------------------------------------------------------------
function getTables($IMPOTS) {
  // $IMPOTS: o nome do arquivo que contém os dados das tabelas $limites, $coeffR, $coeffN
  // o arquivo $IMPOTS existe?
  if (!file_exists($IMPOTS))
    return array("Le fichier $IMPOTS n'existe pas","","","");
  // leitura em bloco do arquivo
  $tables = file($IMPOTS);
  if (!$tables)
    return array("Erreur lors de l'exploitation du fichier $IMPOTS","","","");
  // criação das 3 tabelas — supõe-se que as linhas estejam sintaticamente corretas
  $limites = explode(":", cutNewLineChar($tables[0]));
  $coeffR = explode(":", cutNewLineChar($tables[1]));
  $coeffN = explode(":", cutNewLineChar($tables[2]));
  // fim
  return array("", $limites, $coeffR, $coeffN);
}
?>

Comentários

  • linha 11: a função getTables($IMPOTS) utiliza o arquivo de texto $IMPOTS para extrair as três tabelas ($limites, $coeffR, $coeffN). O resultado gerado é ($erreur, $limites, $coeffR, $coeffN), em que $erreur é uma mensagem de erro, vazia caso não tenha ocorrido nenhum erro.
  • linha 40: a função getTables($IMPOTS).
  • linha 43: a função files_exists(nom_fichier) retorna o valor booleano true se o arquivo nom_fichier existir; caso contrário, retorna o valor booleano false.
  • linha 46: a função file(nom_fichier) lê todo o arquivo de texto nom_fichier. Ela retorna um array em que cada elemento corresponde a uma linha do arquivo de texto. Como, neste caso, o arquivo impots.txt tem três linhas de texto, a função retornará um array com três elementos.
  • linhas 50-52: utilização das três linhas recuperadas para criar os três tabuletos ($limites, $coeffR, $coeffN)

Os resultados obtidos são os mesmos da versão anterior.