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.