ENSET Mohammedia Universit Hassan II Casablanca azizdaaif net
ENSET Mohammedia Université Hassan II Casablanca aziz@daaif. net
Classes et classes abstraites � Interfaces � Accessibilité des membres d’une classe � Membres statiques � Membre ou classe « final » � Méthodes magiques pour : � � La construction et la destruction d’objets � Fonctionnalités génériques (__to. String()) � Gérer le clonage d’objets � Gérer les accesseurs et les mutateurs � Espaces de noms � Outils de gestions des dépendances et d’autochargement des classes
<? php // Fichier : src/metier/Point. php namespace dessin; class Point { // Attributs (Propriétés) private $x; private $y; // Constructeur function __construct($x = 0, $y = 0) { $this->x = $x; $this->y = $y; } // Methodes public function distance(Point $pt) { return sqrt( pow($this->x - $pt->x, 2) + pow($this->y - $pt->y, 2) ); <? php // Inclure le code de la classe require_once "src/dessin/Point. php"; // Utilisation de l'espace de nom use dessinPoint; // Instanciation de la classe $p 1 = new Point(33. 3, 60); echo "<hr>Point[x=". $p 1 ->get. X(). ", y=". $p 1 ->get. Y(). "]"; } // Getters et Setters // Distance de $p 1 par rapport à [0, 0] public function get. X() { $distance = $p 1 ->distance(new Point()); return $this->x; } echo "<hr>Distance arrondie : ". round($distance, 2); public function set. X($x) { $this->x = $x; } public function get. Y() { return $this->y; } public function set. Y($y) { $this->y = $y; } } echo "<hr>Distance : ". $distance;
Classe Abstraite Attributs « protected » Les classes filles y accéderont Méthodes abstraites Doivent être implémentées Par les classes filles Les classes filles définissent d’autres attributs
<? php // Fichier : src/dessin/Figure. php namespace dessin; Déclaration de l’espace de nom // Classe abstraite abstract class Figure { // Attributs protégés Classe Abstraite protected $left = 0; protected $top = 0; protected $width; protected $height; Attributs protégés. Peuvent avoir des valeurs par défaut // Constructeur public function __construct($l, $t, $w, $h){ $this->left = $l; $this->top = $t; Constructeur (Méthode magique!) $this->width = $w; $this->height = $h; } // Méthodes abstraites public abstract function dessiner(apiContext $ctx); Méthodes abstraites public abstract function surface(); public abstract function perimetre(); // Setters et Getters public function get. Left() { Getters et Setters return $this->left; } public function set. Left($left) { $this->left = $left; } // pareil pour les autres attributs } Ici on peut créer une fonction protégée utilitaire (Helper) qui reçoit deux points comme paramètres et retourne un tableau associatif contenant [left, top, width, height]
/** * Méthode Helper get. Dimensions() * @param Point $p 1 Méthode « get. Dimensions() » de la classe abstraite « Figure » * @param Point $p 2 * @return array */ protected function get. Dimensions(Point $p 1, Point $p 2){ $left = min([ $p 1 ->get. X(), $p 2 ->get. X() Veillez à commenter votre code : Certains IDE utilisent les commentaires pour déterminer les types de paramètres et le type retourné. Et + ]); $width = max([ $p 1 ->get. X(), $p 2 ->get. X() ])- $left; $top = min([ $p 1 ->get. Y(), $p 2 ->get. Y() Aérez Votre code : Les paramètres peuvent être étalés sur plusieurs lignes ]); $height = max([ $p 1 ->get. Y(), $p 2 ->get. Y() ])- $top; return [ "left" => $left, "top" => $top, "width" => $width, "height" => $height ]; } Les tableaux associatifs sont plus explicites que les tableaux indexés.
<? php // Fichier : src/dessin/Line. php namespace dessin; require_once "Figure. php"; class Line extends Figure { private $p 1; private $p 2; function __construct(Point $p 1, Point $p 2){ $this->p 1 = $p 1; $this->p 2 = $p 2; $d = $this->get. Dimensions($p 1, $p 2); // appel du constructeur parent L’héritage se fait par le mot clé « extends » . Ne pas oublier d’inclure le source de la classe parente. Appel du constructeur de la classe mère. Ceci est valable pour toutes les méthodes redéfinies dans une classe fille. parent: : __construct( $d['left'], $d['top'], $d['width'], $d['height'] ); <? php // Fichier : test/test_line. php } public function dessiner(apiContext $ctx) { $ctx->draw. Line( $this->p 1 ->get. X(), $this->p 1 ->get. Y(), $this->p 2 ->get. X(), $this->p 2 ->get. Y() ); // inclusion des dépendances require_once ". . /src/dessin/Line. php"; require_once ". . /src/dessin/Point. php"; use dessinLine; use dessinPoint; } public function surface() { return 0; } public function perimetre() { return $this->p 1 ->distance($this->p 2); } $line = new Line(new Point(50, 50), new Point()); echo "<hr>$line"; echo "<hr>Surface : ". $line->surface(); echo "<hr>Perimetre : ". $line->perimetre(); function __to. String(){ return "Line {". $this->p 1. ", ". $this->p 2. "}"; } } Redéfinition de la méthode magique « __tostring() »
<? php // Fichier : src/dessin/Rect. php namespace dessin; <? php // Fichier : test/test_rect. php require_once "Figure. php"; require_once ". . /src/dessin/Rect. php"; class Rect extends Figure{ private $p 1; require_once ". . /src/dessin/Point. php"; private $p 2; function __construct(Point $p 1, Point $p 2){ $this->p 1 = $p 1; $this->p 2 = $p 2; $d = $this->get. Dimensions($p 1, $p 2); use dessinRect; use dessinPoint; parent: : __construct($d['left'], $d['top'], $d['width'], $d['height']); } public function dessiner(apiContext $ctx) { $rect = new Rect(new Point(50, 50), new Point()); $ctx->draw. Rect( $this->p 1 ->get. X(), $this->p 1 ->get. Y(), $this->p 2 ->get. X(), $this->p 2 ->get. Y() ); } public function surface() { return $this->get. Largeur() * $this->get. Hauteur(); } public function perimetre() { return 2 *($this->get. Largeur() + $this->get. Hauteur()); } function __to. String() { return "Rectangle {". $this->p 1. ", ". $this->p 2. "}"; } // Helpers private function get. Largeur() { return abs($this->p 1 ->get. X() - $this->p 2 ->get. X()); } private function get. Hauteur(){ return abs($this->p 1 ->get. Y() - $this->p 2 ->get. Y()); } } echo "<hr>$rect"; echo "<hr>Surface : ". $rect->surface(); echo "<hr>Perimetre : ". $rect->perimetre();
<? php // Fichier : src/dessin/Circle. php <? php // Fichier : test/test_circle. php namespace dessin; require_once "Figure. php"; class Circle extends Figure{ require_once ". . /src/dessin/Circle. php"; require_once ". . /src/dessin/Point. php"; const PI = 3. 14159; private $center; use dessinCircle; private $rayon; use dessinPoint; function __construct(Point $c, $r){ $this->center = $c; $this->rayon = $r; parent: : __construct($c->get. X()-$r, $c->get. Y()-$r, 2*$r); $circle = new Circle(new Point(50, 50), 10); } public function dessiner(apiContext $ctx) { $ctx->draw. Circle( $this->center->get. X(), echo "<hr>Surface : ". $circle->surface(); $this->center->get. Y(), echo "<hr>Perimetre : ". $circle->perimetre(); $this->rayon ); } public function surface() { return self: : PI * $this->rayon; } public function perimetre() { return 2 * self: : PI * $this->rayon; } function __to. String(){ return "Circle {". $this->center. ", ". $this->rayon. "}"; } } echo "<hr>$circle";
Ici, on suppose que toutes les classe se trouvent dans le dossier « src » , et que : • L’espace de noms correspond à l’arborescence de dossiers • Le nom de la classe correspond au nom du fichier avec l’extension «. php » • L’alternative à cette approche est d’utiliser l’autoloading psr-4 (Voir Composer) <? php // Fichier : autoload. php // __autoload() appelée en dernier recours function __autoload($class. Name){ $parts = str_replace( '\', // Chaine à remplacer DIRECTORY_SEPARATOR, // Séparateur dépend de l'OS $class. Name // le nom qualifié de la classe ); // Inclusion du source de la classe require_once __dir__. "/src/$parts. php"; }
<? php // Fichier : src/dessin/api/Context. php namespace dessinapi; // Classe abstraite // Elle représente le contexte du dessin abstract class Context { // Quelques attributs protected $width; protected $height; // Méthodes abstraites abstract function draw. Line($x 1, $y 1, $x 2, $y 2); abstract function draw. Circle($cx, $cy, $r); abstract function draw. Rect($x 1, $y 1, $x 2, $y 2); // Ici d'autres méthodes de dessin. . . // Méthode qui permet de faire le rendu du graphique abstract function render(); // Getters et Setters function get. Height(){ return $this->height; } function get. Width(){ return $this->width; } }
<? php // Fichier src/dessin/api/Context. SVGImpl. php namespace dessinapi; require_once "Context. php"; // suite function render() { $w = $this->width; $h = $this->height; class Context. SVGImpl extends Context { private $figures = []; function __construct($w=200, $h=160){ $svg = "<svg width='$w' height='$h' style='border: 1 px red dashed'>"; array_unshift($this->figures, $svg); $this->width = $w; $this->height = $h; $this->figures[] = "</svg>"; } return implode('n', $this->figures); function draw. Line($x 1, $y 1, $x 2, $y 2) { } $this->figures[] = private function get. Min($x 1, $x 2){ "<line x 1='$x 1' y 1='$y 1' x 2='$x 2' y 2='$y 2' ". return ($x 1<$x 2) ? $x 1 : $x 2; " style='stroke: black; stroke-width: 3; fill: none' />"; } } private function get. Dim($x 1, $x 2){ function draw. Circle($cx, $cy, $r) { return abs($x 1 -$x 2); } $this->figures[] = "<circle cx='$cx' cy='$cy' r='$r' ". " style='stroke: black; stroke-width: 3; fill: none' />"; } function draw. Rect($x 1, $y 1, $x 2, $y 2) { $x = $this->get. Min($x 1, $x 2); $y = $this->get. Min($y 1, $y 2); $w = $this->get. Dim($x 1, $x 2); $h = $this->get. Dim($y 1, $y 2); $this->figures[] = "<rect x='$x' y='$y' width='$w' height='$h' ". " style='stroke: #000; stroke-width: 3; fill: none' />"; } }
<? php // Fichier : test/test_context_svg. php require_once ". . /autoload. php"; use dessinPoint; use dessinRect; use dessinCircle; use dessinLine; use dessinapiContext. SVGImpl; $p 1 = new Point(120, 80); $figures = array(); $figures[] = new Rect($p 1, new Point()); $figures[] = new Circle($p 1, 60); $figures[] = new Line($p 1, new Point()); $ctx = new Context. SVGImpl(); foreach ($figures as $figure){ echo "<hr>$figure"; echo " Surface : ". $figure->surface(); echo " Perimetre : ". $figure->perimetre(); $figure->dessiner($ctx); } ? > <hr> <? = $ctx->render()? >
<? php // Fichier src/dessin/api/Context. Img. Impl. php // Suite function draw. Circle($cx, $cy, $r) { namespace dessinapi; imagearc( // Fonction de lib GD de php $this->image, $cx, $cy, 2*$r, 0, 359. 99, class Context. Img. Impl extends Context{ $this->default. Color private $image; ); private $default. Color; } function draw. Rect($x 1, $y 1, $x 2, $y 2) { function __construct($width=200, $height=160){ imagerectangle( // Fonction de lib GD de php $this->width = $width ; $this->height = $height; $this->image, $this->image = imagecreatetruecolor($width, $height); $this->get. Min($x 1, $x 2), $this->get. Min($y 1, $y 2), $bg = $this->color(255, 255); $this->get. Max($x 1, $x 2), $this->get. Max($y 1, $y 2), imagefill($this->image, 0, 0, $bg ); $this->default. Color $red = $this->color(255, 200); imagerectangle($this->image, 0, 0, $width-1, $height-1, $red); } imagesetthickness($this->image, 2); function render() { $this->default. Color = $this->color(0, 0, 0); $filename = "im_". time(). "_gen. png"; imageantialias($this->image, true); imagepng($this->image, $filename); } return $filename; function draw. Line($x 1, $y 1, $x 2, $y 2){ } imageline( // Fonction de lib GD de php private function get. Min($x 1, $x 2){ $this->image, return ($x 1<$x 2) ? $x 1 : $x 2; $x 1, $y 1, $x 2, $y 2, } $this->default. Color private function get. Max($x 1, $x 2) { ); return ($x 1 < $x 2) ? $x 2 : $x 1; } } function color($r, $g, $b){ return imagecolorallocate($this->image, $r, $g, $b); } }
<? php // Fichier : test/test_context_img. php require_once ". . /autoload. php"; use dessinPoint; use dessinRect; use dessinCircle; use dessinLine; use dessinapiContext. SVGImpl; $p 1 = new Point(120, 80); $figures = array(); $figures[] = new Rect($p 1, new Point()); $figures[] = new Circle($p 1, 60); $figures[] = new Line($p 1, new Point()); $ctx = new dessinapiContext. Img. Impl(); foreach ($figures as $figure){ echo "<hr>$figure"; echo " Surface : ". $figure->surface(); echo " Perimetre : ". $figure->perimetre(); $figure->dessiner($ctx); } ? > <hr> <img src="<? = $ctx->render()? >" />
<? php // Fichier src/dessin/Graphique. php namespace dessin; use dessinapiContext; Association d’agrégation avec « Figure » class Graphique { private $figures = array(); private $context; function __construct(Context $ctx) { Association d’agrégation avec « Context » $this->context = $ctx; } function appen. Fig(Figure $fig) { $this->figures[] = $fig; Injection des dépendances return $this; } function prepend. Fig(Figure $fig) { array_unshift($this->figures, $fig); return $this; Implémentation de l’interface } function dessiner() { foreach($this->figures as $fig) $fig->dessiner($this->context); return $this->context->render(); } function get. Context() { return $this->context; } function set. Context(Context $ctx) { $this->context = $ctx ; } } Getter et Setter.
<? php // Fichier test/test_graph. php require_once ". . /autoload. php"; use dessinapiContext. SVGImpl; use dessinapiContext. Img. Impl; use dessinGraphique; use dessinPoint; use dessinLine; use dessinCircle; use dessinRect; $p 1 = new Point(80, 60); $p 2 = new Point(180, 140); $p 3 = new Point(20, 140); // Injection du context SVG $graph = new Graphique(new Context. SVGImpl()); $graph // ici on peut chainer l'appel ->appen. Fig(new Line($p 1, $p 3)) ->prepend. Fig(new Rect($p 1, $p 2)) ->appen. Fig(new Circle($p 1, 50)); echo "<hr>". $graph->dessiner(); // Injection du context Image $graph->set. Context(new Context. Img. Impl()); echo "<hr><img src='". $graph->dessiner(). "' />";
<? php // Fichier : src/Histo. php // Suite // -- EXEMPLE D’UTILISATION DE L’API -- // function render(){ $count = count($this->data); use dessinapiContext; $Height. Ratio = $this->height / $this->max; use dessinGraphique; $Width. Ratio = $this->width / $count; use dessinPoint; $i = 0; use dessinRect; foreach($this->data as $data){ $x = $i * $Width. Ratio; class Histo { $y = $this->height - $data * $Height. Ratio; private $graphic; // Graphique private $data; // array private $max; // Valeur maximale supposée private $width; // Largeur de l'histogramme $this->graphic->appen. Fig( new Rect( new Point($x + 4, $y), new Point( private $height; // Hauteur de l'histogramme $x + $Width. Ratio - 4, // Contexte (SVG, IMG, ou autre) et Données $this->height function __construct(Context $ctx, array $data, $max) { ) $this->graphic = new Graphique($ctx); ) $this->data = $data; ); $this->max = $max; $i++; $this->width = } $this->graphic->get. Context()->get. Width(); return $this->graphic->dessiner(); $this->height = $this->graphic->get. Context()->get. Height(); } } }
<? php // Fichier : test/test_histo. php require_once ". . /autoload. php"; // Données $data = [198, 222, 90, 38, 123, 290, 200, 50, 130]; // Imlémentaion SVG $histo = new Histo( new dessinapiContext. SVGImpl(), $data, 300 ); echo $histo->render(); // Implémentation Image (GD) $histo = new Histo( new dessinapiContext. Img. Impl(), $data, 300 ); echo "<hr><img src='". $histo->render(). "' />";
<? php // Fichier src/dessin/Graphique. php namespace dessin; use dessinapiContext; class Graphique implements Array. Access{ private $figures = array(); private $context; On utilise le mot clé « implements » pour implémenter une interface. L’interface « Array. Access » est définie dans PHP et a pour espace de nom « » //. . . Ici les méthodes déjà implémentées // Implémentation de l’interface Array. Acces public function offset. Exists($offset){ Vérifie si une clé donnée existe return isset($this->figures[$offset]); } public function offset. Get($offset) { return isset($this->figures[$offset]) ? $this->figures[$offset] Lecture d’une valeur correspondant à une clé donnée : null; } public function offset. Set($offset, $value){ if(is_null($offset)) Mise à jour de l’entrée du tableau correspondant à une clé donnée (ou non) $this->figures[] = $value; else $this->figures[$offset] = $value; } public function offset. Unset($offset) { unset($this->figures[$offset]); } } Destruction de l’entrée du tableau correspondant à une clé donnée
<? php // Fichier test/test_graph 2. php require_once ". . /autoload. php"; use dessinapiContext. SVGImpl; use dessinapiContext. Img. Impl; use dessinGraphique; use dessinPoint; use dessinLine; use dessinCircle; use dessinRect; $p 1 = new Point(80, 60); $p 2 = new Point(180, 140); $p 3 = new Point(20, 140); // Injection du context SVG $graph = new Graphique(new Context. SVGImpl()); // L'objet se comporte comme un tableau $graph[] = new Line($p 1, $p 3); $graph[] = new Rect($p 1, $p 2); $graph[] = new Circle($p 1, 50); echo "<hr>". $graph->dessiner(); // Injection du context Image $graph->set. Context(new Context. Img. Impl()); echo "<hr><img src='". $graph->dessiner(). "' />";
- Slides: 25