Skip to content

4. 应用练习 – 税费计算

4.1. 问题

我们的目标是编写一个程序来计算纳税人的税款。我们将考虑一个简化案例,即纳税人仅需申报工资收入:

  • 员工的股份数量按以下公式计算:若未婚,则 nbParts = nbEnfants / 2 + 1;若已婚,则 nbParts = nbEnfants / 2 + 2,其中 nbEnfants 表示其子女数量。
  • 我们计算他们的应税收入 R = 0.72 * S,其中 S 是他们的年薪
  • 我们计算其家庭系数 Q = R / N

根据以下数据,我们计算其应纳税额 I

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
4900
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

每行有 3 个字段。要计算税款 I,我们寻找第一个满足 QF <= 字段1 的行。例如,如果 QF = 30000,我们将找到该行

    24740        0.15        2072.5

此时,Tax I 等于 0.15*R - 2072.5*nbParts。如果 QF 使得条件 QF<=field1 永远不成立,则使用最后一行中的系数。这里:

    0                0.65        49062

由此可得税额 I = 0.65*R – 49062*nbParts。

4.2. 使用数组的版本 (impots_01)

我们提供一个初始程序,其中:

  • 用于计算税款的数据存储在三个数组中(limits、coeffR、coeffN)
  • 纳税人数据(已婚、子女、工资)存储在第一个文本文件中
  • 税款计算结果(已婚、子女、工资、税额)存储在第二个文本文件中

<?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]);
}
?>

数据文件 data.txt(已婚、子女、工资):

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

针对所得结果生成的 results.txt 文件(已婚、子女、薪资、税款):

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

注释

  • 第4行:包含纳税人数据(已婚、子女、工资)的文本文件名称
  • 第5行:包含税款计算结果(婚姻状况、子女、工资、税额)的文本文件名称
  • 第6–8行:用于计算税款的三个数据表
  • 第11–15行:打开纳税人数据文件进行读取
  • 第18–22行:打开结果文件以进行写入
  • 第25行:循环读取纳税人文件中的行(已婚、子女、工资)
  • 第 27 行:移除换行符
  • 第29行:提取该行的组成部分(婚姻状况、子女、工资)
  • 第 31 行:计算税额
  • 第 33 行:将税额存储到结果文件中
  • 第 37-38 行:纳税人文件处理完毕后,关闭文件
  • 第 44 行:该函数用于从字符串 $line 中移除换行符。在 Windows 系统中,换行符为字符串 "\r\n";在 Unix 系统中,换行符为 "\n"。处理结果是去除了换行符的原始输入字符串。
  • 第 47-48 行:substr($string, $start, $size) 返回 $string 中从字符 $start 开始、长度不超过 $size 的子字符串。
  • 第 63 行:strtolower($string)$string 转换为小写
  • 第 76 行:array_push($array, $element)$element 添加到 $array 的末尾。请注意,$limits 数组是以值传递的方式传递给 calculateTax 函数的第 56 行。因此,此项元素的添加是在实际参数的副本上进行的,而实际参数本身保持不变。
  • 第 84 行:floor($x) 函数返回小于 $x 的最小整数值。

4.3. 使用文本文件的版本 (impots_02)

此新版本与前一版本的唯一区别在于,计算税款所需的数据($limites、$coeffR、$coeffN)现在存储在一个文本文件中,格式如下:

文件 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

新版本仅需从 [impots.txt] 文件中读取数据,并将其放入三个数组($limites、$coeffR、$coeffN)中。这使我们回到了之前的案例。我们仅展示更改部分:


<?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);
}
?>

注释

  • 第 11 行:函数 getTables($IMPOTS) 处理文本文件 $IMPOTS 以提取三个表格 ($limites, $coeffR, $coeffN)。返回的结果为 ($error, $limites, $coeffR, $coeffN),其中 $error 是一个错误消息;若未发生错误,则其值为空。
  • 第 40 行:getTables($IMPOTS) 函数。
  • 第 43 行:函数 files_exists(filename) 若文件 filename 存在则返回布尔值 true,否则返回 false
  • 第 46 行:file(filename) 函数读取文本文件 filename 的全部内容。它返回一个数组,其中每个元素代表文本文件中的一行。由于 impots.txt 文件包含三行文本,该函数将返回一个包含三个元素的数组。
  • 第 50–52 行:使用读取到的三行文本创建三个数组($limits、$coeffR、$coeffN

所得结果与上一版本的结果相同。