Le but de ce tp est d'illustrer en PHP l'héritage sur un exemple classique de géometrie; les polygones et leurs spécialisation en rectangles, en triangles etc....
Un polygones sera caractériser par ses sommets qui sont des points.
Point.php
, une classe pour
representer des points en 2 dimensions.
Elle comprendra au moins 1 constructeur ainsi qu'une méthode pour
calculer la distance d'un point à un autre et une méthode __toString
pour pouvoir afficher les coordonnées d'un point sous la forme (x,y)
Point.php
:
<?php class Point{ public $x; public $y; //un constructeur de point function __construct($x,$y){ $this->x = $x; $this->y = $y; } //distance du point courant au point p public function distance($p){ //sqrt donne la racine carré return sqrt( ($this->x-$p->x)*($this->x-$p->x) + ($this->y-$p->y)*($this->y-$p->y)); } /* pour l'affichage: dans tout les contextes où une chaine est attendue et où on fourni un point, il sera automatiquement converti en chaine par la fonction __toString */ public function __toString(){ return "(".$this->x.",".$this->y.")"; } } ?>Pour le tester, on peut écrire un fichier de test
testPoint.php
<?php require "Point.php"; $p1=new Point(3,4); $p2=new Point(1,3); echo "la distance entre $p1 et $p2 est :".$p1->distance($p2)."\n"; //comme $x et $y sont public vous pouvez ecrire $p2->x=42; echo '$p2->x vaut '.$p2->x ."\n"; ?>qui devrait afficher
la distance entre (3,4) et (1,3) est :2.2360679774998 $p2->x vaut 42
Si vous mettez les coordonnées x
et y
en private
... private $x; private $y;vous aurez alors le message d'erreur
Fatal error: Cannot access private property Point::$xCar
x
et y
ne sont plus visible à l'exterieur
de la classe Point
.
On peut definir des fonction pour y acceder en lecture et en
ecriture. Cela permet de d'affranchir l'utilisateur de la classe de la
fonçon dont les donnés sont implementées.
N'hesitez pas à introduire des erreurs pour voir ce que cela donne. Par exemple si vous creer un point sans donner les coordonnées:
$p3=new Point();vous devriez avoir un message du genre
HP Warning: Missing argument 1 for Point::__construct(),Il est toujours important de s'entrainer a comprendre les messages d'erreurs et les avertissements
Ceux qui auraient des difficultés avec le calcul de la distance peuvent consulter wikipedia
Polygone.php
, une classe polygone
où un polygome est un ensemble (un tableau) de points. Elle aura au
moins un constructeur prenant en arguments les points qui composent le
polygone.
<?php // Un Polygone étant composé de Point, on charge la classe qui les represente. // on poura le supprimer si on opte pour l'autoload (http://php.net/manual/fr/function.autoload.php) require_once("Point.php"); class Polygone { // declaration d'un tableau de points //Protected signifit que cette donnée n'est visible que dans la classe polygone et celle qui en héritent protected $sommets; //Constructeur prenant un tableau de point en argument public function __construct($tableauDePoint){ $this->sommets=array(); //initialisation a vide du tableau $nb=count($tableauDePoint); for($i= 0;$i < $nb;$i++){ $p=$this->sommets[$i]=$tableauDePoint[$i]; } } } ?>
On ne sait pas à l'avance de combien de point est composé le polygone,
c'est au momment de la creation qu'on va lui passer les points qui le compose.
Pour gerer ce nombre d'argument variable on a opté pour les passer dans un tableau.
On peut le tester par exemple avec un fichier PolygoneTabTest.php
<?php require_once("Polygone.php"); $p=new Polygone(array(new Point(2,3),new Point(4,5))); var_dump($p) ?>qui affichera:
object(Polygone)#1 (1) { ["sommets":protected]=> array(2) { [0]=> object(Point)#2 (2) { ["x"]=> int(2) ["y"]=> int(3) } [1]=> object(Point)#3 (2) { ["x"]=> int(4) ["y"]=> int(5) } } }
Une autre solution dans l'ecriture du constructeur est d'utiliser, les fonctions func_num_args et func_get_arg permettant de gerer les arguments passés au construteur.
<?php .... //Constructeur vide ou prenrant des point en aguments public function __construct(){ $this->sommets=array(); $nb=func_num_args(); //nombre d'arg passes au constructeur for($i= 0;$i < $nb;$i++){ $p=func_get_arg($i); //argument d'indice i $this->sommets[$i]=new Point($p->x,$p->y); } } ?>
.... //Pour retrouver le nombre de sommet public function nbrSommet(){ return count($sommets); } //Pour calculer le perimetre //on calcule la distance de chaque sommet au suivant //puis du dernier au premier (indice 0) //et on fait la somme de ces distances public function perimetre(){ $result=0; $nbs; for ($i=0;$i < count($this->sommets)-1;$i++){ $result = $result + $this->sommets[$i]->distance($this->sommets[$i+1]); } if(count($this->sommets)>0) return $result +($this->sommets[0]->distance($this->sommets[count($this->sommets) -1])) ; else return 0; } ...
__toString
pour l'affichage d'un polygone par
l'affichage de la liste des sommets (les points).
//Pour l'affichage public function __toString(){ $result =""; for ($i=0;$i < count($this->sommets);$i++){ $result = $result ." , ".$this->sommets[$i]; } return $result."
"; } }
testPolynome.php
pour tester vos polygones et leur methodes.
Par exemple
$P= new Polygone(new Point(1,1), new Point(2,2),new Point(1,2)); print("je suis un polygone de sommet(s)".$P); print("et de perimetre ".$P->perimetre()); echo "affichera:
";
<?php //pour l'autoload function __autoload($class) { require_once($class . '.php'); } //creation d'un polygone (seconde version du constructeur) $P= new Polygone(new Point(1,1), new Point(2,2),new Point(1,2)); print("je suis un polygone de sommet(s)".$P); print("et de perimetre ".$P->perimetre()); echo "
"; ?>
Rectangle.php
une classe
rectangle qui spécialise les polygones. Le constructeurs prend
deux points en argument correspondants aux coins supérieur gauche et inférieur droit)
<?php //La classe rectangle qui herite des polynomes class Rectangle extends Polygone { //Constructeur prenant les coins superieur gauche et inferieur droit public function __construct($x,$y){ $this->sommets=array($x,new Point($y->x,$x->y),$y,new Point($x->x,$y->y)); } ?>
... ///////// Ajout de fonctions specifiques aux rectangles //Calcul de la longueur public function longueur(){ return abs($this->sommets[0]->x - $this->sommets[2]->x); } //calcul de la largeur public function largeur(){ return abs($this->sommets[0]->y - $this->sommets[2]->y); } ...
... //Redefinition de la fonction de calcul du perimetre public function perimetre(){ return 2*($this->longueur()+$this->largeur()); } } ...
<?php //La classe triangle qui herite des polynomes class Triangle extends Polygone { //Constructeur prenant les coins superieur gauche et inferieur droit public function __construct($x,$y,$z){ parent::__construct($x,$y,$z); } }
public function equilateral(){ $s=$this->sommets; // attention s'agissant de float, les erreurs de precision // dans le calcul de la distance empeche de comparer les distance // avec une egalite. Nous utilisons donc des differences et // on fixe ici la precision à 1E-15 return ( abs($s[0]->distance($s[1])- $s[1]->distance($s[2]))<1E-15 && abs($s[1]->distance($s[2]) -$s[2]->distance($s[0]))<1E-15); } }
N'oublier pas d'utiliser l'autoloading dans le fichier de test.