11. Übung IMPOTS mit einem Service WEB und einer dreischichtigen Architektur
Wir werden die Übung IMPOTS (siehe Abschnitte 4.2, 4.3, 6) wieder aufnehmen und daraus eine Client-Server-Anwendung erstellen. Das Server-Skript wird in drei Elemente unterteilt:
- eine Schicht namens [dao] (Data Access Objects), die den Datenaustausch mit der Datenbank MySQL übernimmt
- eine Schicht namens [métier], die die Steuerberechnung durchführt
- eine Schicht namens [web], die den Datenaustausch mit den Web-Clients übernimmt.
![]() |
Das Client-Skript [1]:
- übermittelt dem Serverskript die drei Informationen ($marié, $enfants, $salaire), die für die Steuerberechnung erforderlich sind
- zeigt die Antwort des Servers auf der Konsole an
Das Serverskript [2] besteht aus der Serverschicht [web].
- Zu Beginn einer neuen Client-Sitzung speichert es die Daten aus den Datenbanken MySQL und [dbimpots] in Arrays. Dazu greift es auf die Schicht [dao] zurück. Die so erstellten Arrays werden in die Clientsitzung übernommen, damit sie in späteren Abfragen des Clients verwendet werden können.
- Bei einer Client-Anfrage übergibt er die drei Informationen ($marié, $enfants, $salaire) an die Schicht [métier] weiter, die die Steuer $impot berechnet.
- Das Server-Skript gibt die berechnete Steuer $impôt zurück.
11.1. Das Client-Skript (clients_impots_05_web)
Das Client-Skript fungiert als Client des Webdienstes zur Steuerberechnung. Es sendet (POST) Parameter in folgender Form an den Server:
params=$verheiratet,$Kinder,$Gehalt, wobei
- $marié die Zeichenfolge oui oder non ist,
- $enfants die Anzahl der Kinder ist,
- $salaire das Gehalt des Steuerpflichtigen
Er findet die drei vorgenannten Parameter in einer Textdatei [data.txt] in der Form (verheiratet, Kinder, Gehalt):
Das Client-Skript
- liest die Textdatei [data.txt] Zeile für Zeile ein
- sendet die Zeichenfolge „params=$marié,$enfants,$salaire“ an den Webdienst zur Steuerberechnung
- und ruft die Antwort des Dienstes ab. Diese kann zwei Formen annehmen:
- speichert die Antwort des Servers in einer Textdatei [resultats.txt] in einer der beiden folgenden Formen:
Der Code des Client-Skripts lautet wie folgt:
<?php
// Steuerkunde
// Fehlerbehandlung
ini_set("display_errors", "off");
// ---------------------------------------------------------------------------------
// eine Klasse mit Hilfsfunktionen
class Utilitaires {
function cutNewLinechar($ligne) {
...
}
}
// main -----------------------------------------------------
// Definition der Konstanten
$DATA = "data.txt";
$RESULTATS = "resultats.txt";
// Serverdaten
$HOTE = "localhost";
$PORT = 80;
$urlServeur = "/exemples-web/impots_05_web.php";
// Angaben zu den Steuerpflichtigen (Familienstand, Anzahl der Kinder, Jahresgehalt)
// wurden in die Textdatei $DATA mit jeweils einer Zeile pro Steuerpflichtigen geschrieben
// Die Ergebnisse (Familienstand, Anzahl der Kinder, Jahresgehalt, zu zahlende Steuer)
// oder (Familienstand, Anzahl der Kinder, Jahresgehalt, Fehlermeldung) werden in
// in die Textdatei $RESULTATS, wobei pro Zeile ein Ergebnis steht
// Klasse „Hilfsprogramme“
$u = new Utilitaires();
// Öffnen der Steuerzahlerdatei
$data = fopen($DATA, "r");
if (!$data) {
print "Impossible d'ouvrir en lecture le fichier des données [$DATA]\n";
exit;
}
// Öffnen der Ergebnisdatei
$résultats = fopen($RESULTATS, "w");
if (!$résultats) {
print "Impossible de créer le fichier des résultats [$RESULTATS]\n";
exit;
}
// Auswertung der aktuellen Zeile der Steuerzahler-Datendatei
while ($ligne = fgets($data, 100)) {
// Eventuelles Zeilenendezeichen wird entfernt
$ligne = $u->cutNewLineChar($ligne);
// die drei Felder „verheiratet:Kinder:Gehalt“ werden extrahiert, die $ligne bilden
list($marié, $enfants, $salaire) = explode(",", $ligne);
// Die Steuer wird berechnet
list($erreur, $impôt) = calculerImpot($HOTE, $PORT, $urlServeur, $cookie, array($marié, $enfants, $salaire));
// Das Ergebnis wird eingetragen
$résultat = $erreur ? "$marié:$enfants:$salaire:$erreur" : "$marié:$enfants:$salaire:$impôt";
fputs($résultats, "$résultat\n");
// Nächster Datensatz
}
// Dateien werden geschlossen
fclose($data);
fclose($résultats);
// Ende
print "Terminé...\n";
exit;
function calculerImpot($HOTE, $PORT, $urlServeur, &$cookie, $params) {
// verbindet den Client mit ($HOTE,$PORT,$urlServeur)
// sendet das Cookie $cookie, sofern dieses nicht leer ist. $cookie wird als Referenz übergeben
// sendet $params an den Server
// verarbeitet die einzige vom Server zurückgesendete Zeile
// Aufbau einer Verbindung zum Port 80 von $HOTE
$connexion = fsockopen($HOTE, $PORT);
// Fehler?
if (!$connexion)
return array("erreur lors de la connexion au serveur ($HOTE, $PORT)");
// Die Header des Protokolls HTTP müssen mit einer Leerzeile enden
// POST
fputs($connexion, "POST $urlServeur HTTP/1.1\n");
// Host
fputs($connexion, "Host: localhost\n");
// Verbindung
fputs($connexion, "Connection: close\n");
// Das Cookie wird gesendet, sofern es nicht leer ist
if ($cookie) {
fputs($connexion, "Cookie: $cookie\n");
}//if
// Nun wird die Client-Anweisung nach der Kodierung gesendet
$infos = "params=" . urlencode(implode(",", $params));
// Es wird angegeben, welche Art von Informationen gesendet werden
fputs($connexion, "Content-type: application/x-www-form-urlencoded\n");
// Die Größe (Anzahl der Zeichen) der zu sendenden Informationen wird gesendet
fputs($connexion, "Content-length: " . strlen($infos) . "\n");
// Es wird eine Leerzeile gesendet
fputs($connexion, "\n");
// Die Informationen werden gesendet
fputs($connexion, $infos);
// Die Antwort des Webservers wird angezeigt
// und man achtet darauf, ein eventuelles Cookie abzurufen
while ($ligne = fgets($connexion, 1000)) {
// Cookie – nur bei der ersten Antwort
if (!$cookie) {
if (preg_match("/^Set-Cookie: (.*?)\s*$/", $ligne, $champs)) {
$cookie = $champs[1];
}//if
}
// Sobald eine leere Zeile erscheint, ist die Antwort HTTP beendet
if (trim($ligne) == "") {
break;
}
}//while
// Ergebniszeile lesen
$ligne = fgets($connexion, 1000);
// Die Verbindung wird geschlossen
fclose($connexion);
// Ergebnis berechnen
$erreur="";
$impôt="";
if (preg_match("/^<erreur>(.*?)<\/erreur>\s*$/", $ligne, $champs)) {
$erreur = $champs[1];
} else {
if (preg_match("/^<impot>(.*?)<\/impot>\s*$/", $ligne, $champs)) {
$impôt = $champs[1];
}else{
$erreur="résultat du serveur non exploitable";
}
}
// Rückgabe
return array($erreur, $impôt);
}
Kommentare
Der Code des Client-Skripts enthält bereits bekannte Elemente:
- Zeilen 9–15: Die Klasse [Utilitaires] wurde in Version 3, Abschnitt 6, vorgestellt
- Zeilen 17–68: Das Hauptprogramm entspricht dem in Version 1, Abschnitt 4.2. Es unterscheidet sich davon lediglich durch die Steuerberechnung in Zeile 56.
- Zeile 56: Die Funktion zur Steuerberechnung akzeptiert folgende Parameter:
- $HOTE, $PORT, $urlServeur: ermöglichen die Verbindung zum Webdienst
- $cookie: ist das Sitzungs-Cookie. Dieser Parameter wird per Referenz übergeben. Sein Wert wird von der Funktion zur Steuerberechnung festgelegt. Beim ersten Aufruf hat er keinen Wert. Danach hat er einen.
- array($marié, $enfants, $salaire): stellt eine Zeile der Datei [data.txt] dar
Die Funktion zur Steuerberechnung gibt ein Array mit zwei Ergebnissen zurück ($erreur, $impôt), wobei $erreur eine eventuelle Fehlermeldung und $impôt der Steuerbetrag ist.
- Zeilen 70 – 134: Hier handelt es sich um einen klassischen HTTP-Client, wie wir ihn schon oft gesehen haben. Folgende Punkte sind zu beachten:
- Zeile 83: Die Parameter ($marié, $enfants, $salaire) werden über einen POST an den Server übermittelt
- Zeilen 89–91: Verfügt der Client über eine Sitzungs-ID, sendet er diese an den Server
- Zeile 93: Erstellung des Parameters params
- Zeile 101: Senden des Parameters params
- Zeilen 104–115: Der Client liest alle vom Server gesendeten HTTP-Header, bis er auf die leere Zeile am Ende der Header stößt. Dabei nutzt er die Gelegenheit, um die Sitzungs-ID aus der Antwort auf seine erste Anfrage abzurufen.
- Zeilen 123–125: Eine mögliche Zeile der Form <erreur>message</erreur> wird verarbeitet
- Zeilen 126–128: Das Gleiche wird mit einer möglichen Zeile der Form <impot>montant</impot> durchgeführt
- Zeile 133: Das Ergebnis wird ausgegeben
11.2. Der Webdienst zur Steuerberechnung
Wir befassen uns hier mit den drei Skripten, aus denen der Server besteht:
![]() |
Das entsprechende NetBeans-Projekt lautet wie folgt:
![]() |
In [1] besteht der Server aus den folgenden Skripten:
- [impots_05_entites] enthält die vom Server verwendeten Klassen
- [impots_05_dao] enthält die Klassen und Schnittstellen der Schicht [dao]
- [impots_05_metier] enthält die Klassen und Schnittstellen der Schicht [metier]
- [impots_05_web] enthält die Klassen und Schnittstellen der Schicht [dao]
Zunächst stellen wir zwei Klassen vor, die von den verschiedenen Schichten des Webdienstes verwendet werden.
11.2.1. Die Entitäten des Webdienstes (impots_05_entites)
Die Datenbank MySQL [dbimpots] enthält eine Tabelle [impots], die die für die Steuerberechnung erforderlichen Daten [1] enthält:
![]() |
Wir speichern die Daten der Tabellen MySQL und [impots] in einem Objektarray Tranche, wobei Tranche die folgende Klasse ist:
<?php
// eine Steuerklasse
class Tranche {
// private Felder
private $limite;
private $coeffR;
private $coeffN;
// Getter und Setter
public function getLimite() {
return $this->limite;
}
public function setLimite($limite) {
$this->limite = $limite;
}
public function getCoeffR() {
return $this->coeffR;
}
public function setCoeffR($coeffR) {
$this->coeffR = $coeffR;
}
public function getCoeffN() {
return $this->coeffN;
}
public function setCoeffN($coeffN) {
$this->coeffN = $coeffN;
}
// Konstruktor
public function __construct($limite, $coeffR, $coeffN) {
$this->setLimite($limite);
$this->setCoeffR($coeffR);
$this->setCoeffN($coeffN);
}
// toString
public function __toString(){
return "[$this->limite,$this->coeffR,$this->coeffN]";
}
}
Die privaten Felder [$limite, $coeffR, $coeffN] dienen dazu, die Spalten [limites, coeffR, coeffN] einer Zeile der Tabelle MySQL [impots] zu speichern.
Außerdem wird der Servercode eine eigene Ausnahme verwenden, nämlich die Klasse ImpotsException:
- Zeile 1: Die Klasse [ImpotsException] leitet sich von der in PHP vordefinierten Klasse [Exception] ab 5
- Zeile 3: Der Konstruktor der Klasse [ImpotsException] akzeptiert zwei Parameter:
- $message: eine Fehlermeldung
- $code: einen Fehlercode
11.2.2. Die Schicht [dao] (impots_05_dao)
Die Schicht [dao] gewährleistet den Zugriff auf die Daten der Datenbank:
![]() |
Die Schicht [dao] weist folgende Schnittstelle auf:
Die Schnittstelle IImpotsDao stellt nur die Funktion getData bereit. Diese Funktion fügt die verschiedenen Zeilen der Tabelle MySQL [dbimpots.impots] in ein Array von Objekten Tranche ein.
Die Implementierungsklasse lautet wie folgt:
<?php
// Dao-Ebene
// Abhängigkeiten
require_once "impots_05_entites.php";
// Konstanten
define("TABLE", "impots");
// -----------------------------------------------------------------
// abstrakte Implementierung
abstract class ImpotsDaoWithPdo implements IImpotsDao {
// private Felder
private $dsn;
private $user;
private $passwd;
private $tranches;
// Getter und Setter
public function getDsn() {
return $this->dsn;
}
public function setDsn($dsn) {
$this->dsn = $dsn;
}
public function getUser() {
return $this->user;
}
public function setUser($user) {
$this->user = $user;
}
public function getPasswd() {
return $this->passwd;
}
public function setPasswd($passwd) {
$this->passwd = $passwd;
}
// Konstruktor
public function __construct($dsn, $user, $passwd) {
// Parameter werden gespeichert
$this->setDsn($dsn);
$this->setUser($user);
$this->setPasswd($passwd);
// Daten aus SGBD abrufen
// verbindet ($user, $pwd) mit der Datenbank $dsn
try {
// Verbindung
$connexion = new PDO($dsn, $user, $passwd, array(PDO::ATTR_PERSISTENT => true));
// Liest die Tabelle $TABLE
$requête = "select limites,coeffR,coeffN from " . TABLE;
// führt die Abfrage $requête über die Verbindung $connexion aus
$statement = $connexion->prepare($requête);
$statement->execute();
// Auswertung des Abfrageergebnisses
while ($colonnes = $statement->fetch()) {
$this->tranches[] = new Tranche($colonnes[0], $colonnes[1], $colonnes[2]);
}
// Verbindung trennen
$connexion=NULL;
} catch (PDOException $e) {
// Rückgabe mit Fehler
throw new ImpotsException($e->getMessage(), 1);
}
}
public function getData(){
return $this->tranches;
}
}
- Zeile 5: Die Implementierung der Schnittstelle [IImpotsDao] benötigt die im Skript [impots_05_entites] definierten Klassen.
- Zeile 11: Definition einer abstrakten Klasse. Eine abstrakte Klasse ist eine Klasse, die nicht instanziiert werden kann. Eine abstrakte Klasse muss zwingend abgeleitet werden, um instanziiert werden zu können. Eine Klasse kann als abstrakt deklariert werden, weil sie nicht instanziiert werden kann (einige ihrer Methoden sind nicht definiert) oder weil man sie nicht instanziieren möchte. In diesem Fall soll die Klasse [ImpotsDaoWithPdo] nicht instanziiert werden. Stattdessen werden abgeleitete Klassen instanziiert.
- Zeile 11: Die Klasse [ImpotsDaoWithPdo] implementiert die Schnittstelle [IImpotsDao]. Sie muss daher die Methode getData definieren. Diese Methode findet sich in den Zeilen 72–74.
- Zeile 14: $dsn (Data Source Name) ist eine Zeichenkette, die die Klasse SGBD und die verwendete Datenbank eindeutig identifiziert.
- Zeile 15: $user identifiziert den Benutzer, der sich bei der Datenbank anmeldet
- Zeile 16: $passwd ist das Passwort des vorherigen Benutzers
- Zeile 17: $tranches ist das Objektarray Tranche, in dem die Tabellen MySQL und [dbimpots.impots] gespeichert werden.
- Zeilen 45–70: Der Konstruktor der Klasse. Dieser Code wurde bereits in Version 4, Abschnitt 8.2, behandelt. Es ist zu beachten, dass die Erstellung des Objekts [ImpotsDaoWithPdo] fehlschlagen kann. In diesem Fall wird eine Ausnahme vom Typ [ImpotsException] ausgelöst.
- Zeilen 72–74: Die Methode [getData] der Schnittstelle [IImpotsDao].
Die Klasse [ImpotsDaoWithPdo] ist für jedes SGBD geeignet. Der Konstruktor der Klasse (Zeile 45) erfordert die Angabe des Data Source Name der Datenbank. Diese Zeichenkette hängt vom verwendeten SGBD ab. Es wurde beschlossen, dem Benutzer der Klasse nicht vorzuschreiben, diesen Data Source Name zu kennen. Für jedes SGBD wird es eine spezielle, von [ImpotsDaoWithPdo] abgeleitete Klasse geben. Für das SGBD MySQL ist dies die folgende Klasse:
class ImpotsDaoWithMySQL extends ImpotsDaoWithPdo {
public function __construct($host, $port, $base, $user, $passwd) {
parent::__construct("mysql:host=$host;dbname=$base;port=$port", $user, $passwd);
}
}
- In Zeile 3 fragt der Hersteller nicht nach dem Data Source Name, sondern lediglich nach dem Namen des Host-Rechners von SGBD ($host), dessen Listening-Port ($port) und dem Namen der Datenbank ($base).
- In Zeile 4 wird der Data Source Name der Datenbank MySQL gebildet und verwendet, um den Konstruktor der übergeordneten Klasse aufzurufen.
Es ist zu beachten, dass zur Anpassung an ein anderes SGBD lediglich die entsprechende von [ImpotsDaoWithPdo] abgeleitete Klasse geschrieben werden muss. Dabei muss jeweils der für das verwendete SGBD spezifische Data Source Name gebildet werden.
11.2.3. Die Schicht [métier] (impots_05_metier)
Die Schicht [metier] enthält die Logik zur Steuerberechnung:
![]() |
Die Schicht [métier] weist folgende Schnittstelle auf:
<?php
// Geschäftsschnittstelle
interface IImpotsMetier {
public function calculerImpot($marié, $enfants, $salaire);
}
Die Schnittstelle [IImpotsMetier] stellt nur eine Methode bereit, nämlich die Methode [calculerImpot], mit der die Steuer eines Steuerpflichtigen anhand der folgenden Parameter berechnet werden kann:
- $marié: Zeichenfolge „ja“ oder „nein“, je nachdem, ob der Steuerpflichtige verheiratet ist oder nicht
- $enfants: die Anzahl der Kinder des Steuerpflichtigen
- $salaire: sein Gehalt
Diese Parameter werden von der Ebene [web] bereitgestellt.
Die Implementierung der Schnittstelle [IImpotsMetier] lautet wie folgt:
// Abhängigkeiten
require_once "impots_05_dao.php";
// ------------------------------------------------------------------
// Implementierungsklasse
class ImpotsMetier implements IImpotsMetier {
// DAO-Schicht
private $dao;
// Objektarray [Tranche]
private $data;
// Getter und Setter
public function getDao() {
return $this->dao;
}
public function setDao($dao) {
$this->dao = $dao;
}
public function setData($data){
$this->data=$data;
}
public function __construct($dao) {
// Die für die Steuerberechnung erforderlichen Daten werden abgerufen
$this->setDao($dao);
$this->setData($this->dao->getData());
}
public function calculerImpot($marié, $enfants, $salaire) {
// $marié: ja, nein
// $enfants: Anzahl der Kinder
// $salaire: Jahresgehalt
// Anzahl der Anteile
$marié = strtolower($marié);
if ($marié == "oui")
$nbParts = $enfants / 2 + 2;
else
$nbParts=$enfants / 2 + 1;
// ein halber Anteil zusätzlich, wenn mindestens 3 Kinder vorhanden sind
if ($enfants >= 3)
$nbParts+=0.5;
// steuerpflichtiges Einkommen
$revenuImposable = 0.72 * $salaire;
// Familienquotient
$quotient = $revenuImposable / $nbParts;
// wird am Ende der Tabelle „Grenzwerte“ eingefügt, um die folgende Schleife zu beenden
$N = count($this->data);
$this->data[$N - 1]->setLimite($quotient);
// Steuerberechnung
$i = 0;
while ($i < $N and $quotient > $this->data[$i]->getLimite()) {
$i++;
}
// da $quotient am Ende des Arrays $limites platziert wurde, wird die vorherige Schleife
// darf nicht über das Array $limites hinausgehen
// Nun kann die Steuer berechnet werden
return floor($revenuImposable * $this->data[$i]->getCoeffR() - $nbParts * $this->data[$i]->getCoeffN());
}
}
- Zeile 2: Die Schicht [métier] benötigt die Klassen der Schicht [dao] sowie die Entitäten (Tranche, ImpotsException).
- Zeile 6: Die Klasse [ImpotsMetier] implementiert die Schnittstelle [IimpotsMetier].
- Zeilen 9–11: Die privaten Felder der Klasse:
- $dao: Referenz auf die Schicht [dao]
- $data: Array von Objekten vom Typ [Tranche], bereitgestellt von der Schicht [dao]
- Zeilen 26–30: Der Konstruktor der Klasse initialisiert die beiden vorherigen Felder. Er erhält als Parameter eine Referenz auf die Schicht [dao].
- Zeilen 32–61: Implementierung der Methode [calculerImpot] der Schnittstelle [IimpotsMetier]. Diese Methode tauchte bereits in Version 1 auf (Abschnitt 4.2).
11.2.4. Die Schicht [web] (impots_05_web)
Die Schicht [metier] enthält die Logik zur Steuerberechnung:
![]() |
Die Schicht [web] besteht aus dem Webdienst, der den Web-Clients antwortet. Zur Erinnerung: Diese senden eine Anfrage an den Webdienst, indem sie den folgenden Parameter übermitteln: params=marié,enfants,salaire. Es handelt sich um einen Webdienst, wie wir ihn in den vorangegangenen Abschnitten erstellt haben. Sein Code lautet wie folgt:
<?php
// Geschäftslogik
require_once "impots_05_metier.php";
// Fehlerbehandlung
ini_set("display_errors", "off");
// Kopfzeile UTF-8
header("Content-Type: text/plain; charset=utf-8");
// ------------------------------------------------------------------------------
// der Steuer-Webdienst
// Definition der Konstanten
$HOTE = "localhost";
$PORT = 3306;
$BASE = "dbimpots";
$USER = "root";
$PWD = "";
// Die für die Steuerberechnung erforderlichen Daten wurden in die MySQL-Tabelle IMPOTS
//, die zur Datenbank $BASE gehört. Die Tabelle hat folgende Struktur
// Grenzwerte decimal(10,2), coeffR decimal(6,2), coeffN decimal(10,2)
// die Parameter der steuerpflichtigen Personen (Familienstand, Anzahl der Kinder, Jahresgehalt)
// werden vom Kunden in der Form „params=Familienstand, Anzahl der Kinder, Jahresgehalt“ übermittelt
// Die Ergebnisse (Familienstand, Anzahl der Kinder, Jahresgehalt, zu zahlende Steuer) werden an den Kunden zurückgesendet
// in der Form <impot>impot</impot>
// oder in der Form <Fehler>Fehler</Fehler>, wenn die Parameter ungültig sind
// wird die Schicht [métier] in der Sitzung abgerufen
session_start();
if (!isset($_SESSION['metier'])) {
// Instanziierung der Schicht [dao] und der Schicht [métier]
try {
$_SESSION['metier'] = new ImpotsMetier(new ImpotsDaoWithMySQL($HOTE, $PORT, $BASE, $USER, $PWD));
} catch (ImpotsException $ie) {
print "<erreur>Erreur : " . utf8_encode($ie->getMessage() . "</erreur>");
exit;
}
}
$metier = $_SESSION['metier'];
// Die vom Client gesendete Zeile wird abgerufen
$params = utf8_encode(htmlspecialchars(strtolower(trim($_POST['params']))));
$items = explode(",", $params);
// Es dürfen nur 3 Parameter vorhanden sein
if (count($items) != 3) {
print "<erreur>[$params] : nombre de paramètres invalides</erreur>\n";
exit;
}//if
// muss der erste Parameter (Familienstand) „ja“ oder „nein“ lauten
$marié = trim($items[0]);
if ($marié != "oui" and $marié != "non") {
print "<erreur>[$params] : 1er paramètre invalide</erreur>\n";
exit;
}//if
// Der zweite Parameter (Anzahl der Kinder) muss eine ganze Zahl sein
if (!preg_match("/^\s*(\d+)\s*$/", $items[1], $champs)) {
print "<erreur>[$params] : 2ième paramètre invalide</erreur>\n";
exit;
}//if
$enfants = $champs[1];
// Der dritte Parameter (Gehalt) muss eine ganze Zahl sein
if (!preg_match("/^\s*(\d+)\s*$/", $items[2], $champs)) {
print "<erreur>[$params] : 3ième paramètre invalide</erreur>\n";
exit;
}//if
$salaire = $champs[1];
// wird die Steuer berechnet
$impôt = $metier->calculerImpot($marié, $enfants, $salaire);
// das Ergebnis wird zurückgegeben
print "<impot>$impôt</impot>\n";
// Ende
exit;
- Zeile 4: Die Schicht [web] benötigt die Klassen der Schicht [métier]
- Zeilen 30–40: Die Referenz auf die Schicht [métier] wird in die Sitzung aufgenommen. Wenn man bedenkt, dass diese Schicht [métier] einen Verweis auf die Schicht [dao] enthält und dass diese wiederum die Daten der Schicht SGBD speichert, wird klar:
- dass die erste Anfrage des Kunden einen Zugriff auf SGBD auslöst
- dass die folgenden Anfragen desselben Kunden die von der Schicht [dao] gespeicherten Daten verwenden. Es erfolgt also kein Zugriff auf SGBD.
- Zeile 34: Aufbau einer Schicht [métier], die mit einer für SGBD implementierten Schicht [dao] zusammenarbeitet MySQL
- Zeilen 35–37: Behandlung eines möglichen Fehlers im vorherigen Vorgang. In diesem Fall wird eine Zeile <erreur>message</erreur> an den Client gesendet.
- Zeile 43: Der vom Kunden gesendete Parameter „params“ wird abgerufen.
- Zeilen 46–49: Die Anzahl der in „params“ gefundenen Informationen wird überprüft.
- Zeilen 51–55: Die Gültigkeit der ersten Information wird überprüft.
- Zeilen 56–60: Gleiches gilt für die zweite Information
- Zeilen 62–66: dasselbe gilt für die dritte
- Zeile 69: Die Schicht [métier] berechnet die Steuer.
- Zeile 71: Das Ergebnis wird an den Kunden gesendet
Ergebnisse
Zur Erinnerung: Der Client [client_impots_web_05] verarbeitet die folgende Datei [data.txt]:
Anhand dieser Zeilen (Familienstand, Kinder, Gehalt) fragt der Client den Steuerberechnungsserver ab und schreibt die Ergebnisse in die Textdatei [resultats.txt]. Nach Ausführung des Clients sieht der Inhalt dieser Datei wie folgt aus:
oui:2:200000:22504
non:2:200000:33388
oui:3:200000:16400
non:3:200000:22504
oui:5:50000:0
non:0:3000000:1354938
wobei jede Zeile die Form (verheiratet, Kinder, Gehalt, berechnete Steuer) hat.






