Skip to content

4. Exercício de aplicação – Cálculo de impostos

4.1. O Problema

O nosso objetivo é escrever um programa para calcular o imposto de um contribuinte. Vamos considerar o caso simplificado de um contribuinte que tem apenas o seu salário para declarar:

  • O número de quotas para o empregado é calculado como nbParts = nbEnfants / 2 + 1 se for solteiro, ou nbEnfants / 2 + 2 se for casado, sendo que nbEnfants é o número de filhos que tem.
  • Calculamos o seu rendimento tributável R = 0,72 * S, em que S é o seu salário anual
  • Calculamos o seu coeficiente familiar Q = R / N

Calculamos o 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 tem 3 campos. Para calcular o imposto I, procuramos a primeira linha em que QF <= campo1. Por exemplo, se QF = 30000, encontraremos 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 condição QF<=field1 nunca seja satisfeita, então são utilizados os coeficientes da última linha. Aqui:

    0                0.65        49062

o que dá o imposto I = 0,65*R – 49062*nbParts.

4.2. Versão com matrizes (impots_01)

Apresentamos um programa inicial em que:

  • os dados necessários para calcular o imposto estão em três matrizes (limits, coeffR, coeffN)
  • os dados do contribuinte (casado, filhos, salário) estão num primeiro ficheiro de texto
  • os resultados do cálculo do imposto (casado, filhos, salário, imposto) estão armazenados num segundo ficheiro de texto

<?php
 
// definition of constants
$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);
 
// reading data
$data = fopen($DATA, "r");
if (!$data) {
  print "Impossible d'ouvrir en lecture le fichier des données [$DATA]\n";
  exit;
}
 
// open results file
$résultats = fopen($RESULTATS, "w");
if (!$résultats) {
  print "Impossible de créer le fichier des résultats [$RESULTATS]\n";
  exit;
}
 
// use the current line of the data file
while ($ligne = fgets($data, 100)) {
  // remove any end-of-line marker
  $ligne = cutNewLineChar($ligne);
  // we retrieve the 3 fields married,children,salary which form $ligne
  list($marié, $enfants, $salaire) = explode(",", $ligne);
  // tax calculation
  $impôt = calculImpots($marié, $enfants, $salaire, $limites, $coeffR, $coeffN);
  // enter the result in the results file
  fputs($résultats, "$marié:$enfants:$salaire:$impôt\n");
  // next taxpayer
}
// close files
fclose($data);
fclose($résultats);
 
// end
exit;
 
// --------------------------------------------------------------------------
function cutNewLinechar($ligne) {
  // delete the end-of-line mark from $ligne if it exists
  $L = strlen($ligne);  // // line length
  while (substr($ligne, $L - 1, 1) == "\n" or substr($ligne, $L - 1, 1) == "\r") {
    $ligne = substr($ligne, 0, $L - 1);
    $L--;
  }
  // end
  return($ligne);
}
 
// --------------------------------------------------------------------------
function calculImpots($marié, $enfants, $salaire, $limites, $coeffR, $coeffN) {
  // $marié : yes, no
  // $enfants : number of children
  // $salaire: annual salary
  // $limites, $coeffR, $coeffN: tax calculation data tables
 
  // number of shares
  $marié = strtolower($marié);
  if ($marié == "oui")
    $nbParts = $enfants / 2 + 2;
  else
    $nbParts=$enfants / 2 + 1;
  // an additional 1/2 share if at least 3 children
  if ($enfants >= 3)
    $nbParts+=0.5;
  // taxable income
  $revenuImposable = 0.72 * $salaire;
  // family quotient
  $quotient = $revenuImposable / $nbParts;
  // is set at the end of the limit table to stop the following loop
  array_push($limites, $quotient);
  // tAX CALCULATION
  $i = 0;
  while ($quotient > $limites[$i])
    $i++;
  // because $quotient has been placed at the end of the $limites array, the previous loop
  // cannot exceed the table $limites
  // now we can calculate the tax
  return floor($revenuImposable * $coeffR[$i] - $nbParts * $coeffN[$i]);
}
?>

O ficheiro 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 ficheiros results.txt (casado, filhos, salário, impostos) para os 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 ficheiro de texto que contém os dados do contribuinte (casado, filhos, salário)
  • linha 5: o nome do ficheiro de texto que contém os resultados (casado, filhos, salário, imposto) do cálculo do imposto
  • Linhas 6–8: as três tabelas de dados utilizadas para calcular o imposto
  • linhas 11-15: abrir o ficheiro de dados do contribuinte para leitura
  • linhas 18–22: abrir o ficheiro de resultados para gravação
  • linha 25: loop para ler as linhas (casado, filhos, salário) do ficheiro do contribuinte
  • linha 27: o caractere 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 é armazenado no ficheiro de resultados
  • linhas 37-38: assim que o ficheiro do contribuinte tiver sido totalmente processado, os ficheiros são fechados
  • linha 44: a função que remove o caractere de fim de linha de uma linha $line. O caractere de fim de linha é a cadeia "\r\n" em sistemas Windows, "\n" em sistemas Unix. O resultado é a cadeia de entrada sem o seu caractere de fim de linha.
  • linhas 47-48: substr($string, $start, $size) devolve a subcadeia de $string que começa no caractere $start e contém, no máximo, $size caracteres.
  • linha 63: strtolower($string) converte $string para minúsculas
  • linha 76: array_push($array, $element) adiciona $element ao final de $array. Note-se que a matriz $limits é passada por valor para a função calculateTax (linha 56). Esta adição de um elemento é, portanto, realizada numa cópia do parâmetro real, que permanece inalterado.
  • linha 84: a função floor($x) devolve o valor inteiro imediatamente inferior a $x.

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

Esta nova versão difere da anterior apenas no facto de os dados ($limites, $coeffR, $coeffN) necessários para calcular o imposto se encontrarem agora num ficheiro de texto com o seguinte formato:

Ficheiro 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 simplesmente lê os dados do ficheiro [impots.txt] e coloca-os em três matrizes ($limites, $coeffR, $coeffN). Isto leva-nos de volta ao caso anterior. Apresentamos apenas as alterações:


<?php
 
// definition of constants
$DATA = "data.txt";
$RESULTATS = "resultats.txt";
$IMPOTS = "impots.txt";
 
// the data required to calculate the tax has been placed in the $IMPOTS file
// one line per table in the form
// val1:val2:val3,...
list($erreur, $limites, $coeffR, $coeffN) = getTables($IMPOTS);
 
// was there a mistake?
if ($erreur) {
  print "$erreur\n";
  exit;
}//if
// reading user data
...
 
// end
exit;
 
// --------------------------------------------------------------------------
function cutNewLinechar($ligne) {
  // delete the end-of-line mark from $ligne if it exists
...
}
 
// --------------------------------------------------------------------------
function calculImpots($marié, $enfants, $salaire, $limites, $coeffR, $coeffN) {
  // $marié : yes, no
  // $enfants : number of children
  // $salaire: annual salary
  // $limites, $coeffR, $coeffN: tax calculation data tables
  ...
}
 
// --------------------------------------------------------------------------
function getTables($IMPOTS) {
  // $IMPOTS: name of the file containing data from tables $limites, $coeffR, $coeffN
  // does the $IMPOTS file exist?
  if (!file_exists($IMPOTS))
    return array("Le fichier $IMPOTS n'existe pas","","","");
  // file block playback
  $tables = file($IMPOTS);
  if (!$tables)
    return array("Erreur lors de l'exploitation du fichier $IMPOTS","","","");
  // create the 3 tables - assume the rows are syntactically correct
  $limites = explode(":", cutNewLineChar($tables[0]));
  $coeffR = explode(":", cutNewLineChar($tables[1]));
  $coeffN = explode(":", cutNewLineChar($tables[2]));
  // end
  return array("", $limites, $coeffR, $coeffN);
}
?>

Comentários

  • Linha 11: A função getTables($IMPOTS) processa o ficheiro de texto $IMPOTS para extrair as três tabelas ($limites, $coeffR, $coeffN). O resultado devolvido é ($error, $limites, $coeffR, $coeffN), em que $error é uma mensagem de erro; fica vazio se não ocorrer nenhum erro.
  • Linha 40: A função getTables($IMPOTS).
  • Linha 43: a função files_exists(filename) retorna o valor booleano true se o ficheiro filename existir e false caso contrário.
  • Linha 46: A função file(filename) lê todo o ficheiro de texto filename. Ela devolve uma matriz em que cada elemento é uma linha do ficheiro de texto. Como o ficheiro impots.txt tem três linhas de texto, a função devolverá uma matriz com três elementos.
  • Linhas 50–52: Use as três linhas recuperadas para criar as três matrizes ($limits, $coeffR, $coeffN)

Os resultados obtidos são os mesmos que os obtidos na versão anterior.