Sommaire
Introduction
La programmation orienté objet, peu importe le langage, apporte une façon de structurer et de penser son code différente.
Elle permet souvent de rendre son code à la fois plus clair et plus efficace.
Mais si c'est si bien que cela, pourquoi ne fait-on pas que de la POO?
Car elle peut être un peu complexe à assimiler et un site de base avec très peu de code php n'a que peu d'intérêt à l'utiliser.
Mais les plus grosses library et framework l'utilise. en PHP on pourrait citer Symfony ou Laravel qui en font énormément usage.
Les classes en POO
Ce que l'on appelle des objets en POO, ce sont des instances de class.
Ces termes peuvent paraître barbare mais on va voir que cela est en fait très simple.
Les classes sont des modèles, des moules sur lesquels se calque chaque nouvel objet que l'on crée.
Certaines class sont déjà disponible dans PHP, et vous en avez peut être déjà fait usage.
$pdo = new PDO($dsn, $username, $password, $options);
$connect = new mysqli("localhost", "user", "password", "database");
Lorsque l'on utilise PDO ou mysqli, on fait en fait appel à des class. On crée une nouvelle instance (d'où l'utilisation du mot
clef new) de la classe PDO ou mysqli.
Cet objet ainsi crée contient toute les fonctions et variables déclaré et défini dans la classe.
Si on crée une deuxième variable contenant un nouveau PDO, les valeurs des variables que celui ci contiendra seront différentes
de celles de notre premier PDO.
Chaque instance d'une classe est un objet différent des autres.
class Form {
}
C'est ainsi qu'on déclare une nouvelle classe.
On utilise le mot clef "class" puis le nom de la classe avant d'ouvrir nos accolades.
Par convention :
- Le nom de la classe commencera par une majuscule.
- On définira une classe par fichier.
- On nommera le fichier php "NomDeLaClass.class.php".
- On rangera toute nos class dans un dossier dédié.
Mais tout cela ne sont que des conventions et non des règles, à vous de faire les choses à votre sauce.
Les propriétés et Méthodes
Voilà deux nouveaux mots barbares qui viennent s'ajouter, les propriétés et les méthodes.
Mais bonne nouvelle, on les connaît déjà, ce sont des choses que l'on a vu et revu mais qui portent simplement un nom
différent quand elles se trouvent à l'interieur d'une classe.
Fin de l'attente, je vous parle ici des variables et des fonctions.
Dans une classe, une variable est appelé propriété, et une fonction, prendra le nom de méthode.
class Form{
private $HTML;
function input(string $name, array $options = []){
$this->label($options["id"]??$name, $options["label"]??$name);
$this->HTML .= "<input
type='". ($options["type"]??"text") ."'
name='$name'
id='". ($options["id"]??$name) ."'
". ($options["required"]??"required") ."><br>";
}
function label(string $for, string $title){
$this->HTML .= "<label for='$for'>$title</label><br>";
}
}
Plusieurs nouveautés ici, on peut voir le mot clef "private", celui ci sera expliqué au chapitre "méthode d'accès".
On a aussi le mot clef "$this" et lui on va s'arrêter dessus un petit moment.
Lorsque l'on souhaite appeler une propriété ou une méthode appartement à la classe dans laquelle on se trouve actuellement,
plutôt que d'écrire son nom comme on en avait l'habitude on utilise ceci:
"$this" suivi de "->" et du "nom". Vous remarquerez que dans le cas de la propriété (variable), le "$" disparait.
Les modes d'accès
Dans l'exemple précédent le mot clef "private" a fait son apparition. Il fait parti des trois modes d'accès avec "public" et
"protected".
Ils doivent être placé avant chaque méthode ou propriété.
Dans l'exemple précédent, on n'en voit toutefois pas devant mes méthodes. Cela est dû au fait que les méthodes sont par défaut
en "public".
Voyons maintenant leurs différences :
- public, cela signifie que la méthode ou la propriété peut être accessible depuis l'interieur de la classe ($this->) autant que depuis l'objet ($variable->) ou depuis un de ses héritiers (on verra cela plus tard).
- protected, quand à lui empêche l'utilisation depuis l'exterieur de la classe, seul les utilisations interne ou par l'héritier sont possible.
- private, est le plus restrictif car seul l'accès depuis la classe même est possible ($this->).
Quand utiliser l'un ou l'autre?
Dans notre exemple la propriété "HTML" n'a pas lieu d'être utilisé par l'utilisateur, de même pour la méthode "label", on peut donc
choisir de les placers en protected ou private, ma classe n'ayant pas pour but d'être hérité, j'ai décidé de leur attribuer private.
Au contraire la méthode "input" a pour but d'être appelé par l'utilisateur, elle est donc public.
Les méthodes Construct et Destruct
Il existe certains méthodes aux effets particuliers, on citera ici Construct et Destruct.
Elles s'écrivent avec deux "_" avant leur nom.
Et elles sont automatiquement appelé à des moments précis, pas besoin de les utiliser soit même.
Voyons construct :
// fichier form.class.php
class Form{
private $HTML;
function __construct($method="POST", $action=""){
$this->HTML = "<form action='$action' method='$method'>" ;
}
}
// fichier form.php
require("../class/Form.class.php");
$form = new Form("GET");
Construct est appelé quand on crée une nouvelle instance de la classe, en donnant à notre class des attributs, ils sont directement transmit à la fonction construct.
Destruct à l'inverse ne prendra pas d'argument. il sera appelé directement à la fin du traitement de PHP, au moment de détruire
toute les variables et juste avant de transmettre les données sous forme HTML.
Si on fait une classe sur la lecture et l'écriture de fichier, on pourrait par exemple donné à Destruct le rôle de fermer le
fichier.
Héritage avec Extends
Plus tôt je parlais de classe enfant et d'héritage, on va ici détaillé ce que c'est.
Le principe de la POO est de découper notre code en différent objets très spécialisé. Hors parfois on aimerait que certaines
de nos classes possèdent des méthodes et propriété déjà défini dans une autre classe.
Prenons cet exemple, on a une classe "Utilisateur" et une classe "Administrateur", cette dernière bien qu'ayant plus de
possibilité, reste un utilisateur. du coups nous ferons cela :
// fichier Utilisateur.class.php
class Utilisateur{
# Propriétés et Méthodes.
}
// fichier Administrateur.class.php
require("Utilisateur.class.php");
class Administrateur extends Utilisateur{
#De nouvelles propriétés et méthodes.
}
En faisant les choses ainsi, lorsque nous allons créer un nouvel administrateur "new Administrateur();". Nous pourrons utiliser toute les méthodes et propriétés (public ou protected) de la class "Utilisateur".
Le mot clef "final".
Avec l'héritage apparaît le mot de clef "final", celui ci peut être placé sur une méthode ou sur une classe.
final class Administrateur extends Utilisateur{
#propriétés et méthodes.
}
Une classe ou une méthode "final" ne peut être hérité, si je tente de faire "class nouvelleclass extends Administrateur{}",
J'obtiendrais une erreur.
Cela permet d'être sûr qu'une classe ou méthode qui n'a pas pour but d'être hérité, ne le sera pas par erreur.
Le mot clef "abstract".
Il peut au contraire y avoir des classes ou des méthodes qui n'ont pour but que d'être hérité.
Ce sera souvent des classes qui regroupent propriétés et méthodes devant être transmise à plusieurs classes.
Au lieu de répéter ces méthodes dans chacune des classes, ont les regroupent dans une classe abstraite afin de les faire hériter
à toute celles qui en ont besoin.
abstract class Utilisateur{
public $nom;
protected function getName(){
return $this->nom;
}
abstract public function setName($n);
}
Notre classe abtraite ne pourra pas être instancié, seulement hérité.
Elle transmettra donc sa propriété et ses deux fonctions mais penchons nous plus sur la fonction abstraite.
On peut voir qu'elle est déclaré mais non défini, les accolades sont absentes et par ce fait rien ne se trouve à l'interieur.
En fait cela va obliger tout ses enfants à définir une fonction respectant les fait suivants :
- Elle doit porter le même nom.
- Elle doit avoir le même nombre de paramètre (argument).
- Son accès doit être équivalent ou plus libre. (de protected on peut en faire un public mais pas un private)
Interfaces et traits
Proche des classes abstraites nous avons les interfaces et les traits.
Prenoms les interfaces, elles ne prennent pas de propriété et seulement des méthodes non défini.
Interfaces
interface Utilisateur{
protected function getName()
public function setName($n);
}
class Administrateur implements Utilisateur{
# méthodes et propriétés.
}
Nous n'avons pas besoin du mot clef "abstract" car dans une interface toute les méthodes sont abstraites.
De plus, au lieu du mot clef "class", on utilise "interface".
Si on utilise pour un héritage le mot clef "extends", pour une interface, on utilisera "implements".
On peut d'ailleurs à la fois hériter une classe et implémenter une interface.
Pour le reste, les interfaces suivent les règles des méthodes abstraites.
Traits
les traits sont là aussi proche des classes abstraites et des interfaces, à la différence qu'on les utilisera plus précisément pour des propriétés et méthodes défini qui seront réutilisé par plusieurs classes.
trait SayUsername{
protected $username;
public function sayIt(){
echo $this->username;
}
}
class Administrateur{
use SayUsername;
}
De cette façon notre classe administrateur peut utiliser les propriétés et méthodes défini dans SayUsername.
Propriété Constante et Méthode Static
Les propriétés constantes et les méthodes statics fonctionne de façon un peu particulière. Celles ci sont accèssible sans instancier la classe. Comme leur nom l'indique, les propriétés constantes ne peuvent être modifié une fois défini.
class Administrateur{
public const ROLE = "admin";
public static getRole(){
echo self::ROLE;
}
}
$role = Administrateur::ROLE;
Administrateur::getRole();
Comme on peut le remarquer, j'accède à mes constantes et static sans avoir à utiliser le mot clef "new" pour instancier ma classe.
de plus pour les utiliser, j'oublie "->" et j'utilise "::".
Pour faire appel à eux hors de ma classe, j'utilise le nom de la classe.
Mais à l'interieur même de ma classe, je remplace "$this" par "self". "$this" pourrait fonctionner mais poser problème dans certains cas
particulier.
Il y a le mot clef "parent" qui peut être aussi utilisé si la static ou la constante est déclaré dans une classe parente qui a été hérité.
Auto chargement des classes
Lorsque l'on travaille en POO, on peut vite se retrouver avec beaucoup de classe, or inclure chacune de nos classes à chaque
page peut être fastidieux et répétitif.
Mais cela tombe bien, il y a une solution :
// fichier Autoloader.class.php
class Autoloader{
static function register(){
spl_autoload_register(array(__CLASS__, 'autoload'));
}
static function autoload($class){
require __DIR__."/$class.class.php";
}
}
// Tout autre fichier:
require "class/Autoloader.class.php";
Autoloader::register();
Une fois cette classe inclus dans notre fichier et la fonction statique "register()" appelé, toute nos classes seront
automatiquement incluse quand on les instenciera avec "new".
"spl_autoload_register" va enregistrer une fonction qui sera appelé automatiquement à chaque fois qu'on tentera d'instencier
une classe.
Si on utilise un système de routing, on peut utiliser cette fonction dans notre fichier principal, et nos classes seront donc
utilisable automatiquement dans n'importe quel fichier.
Les noms d'espace (namespace)
Quand on utilise plusieurs library en plus de ses propres classes, il n'est pas rare que deux classes portent le même nom.
Ce qui peut poser problème lorsque l'on souhaite en sélectionner une plutôt qu'une autre.
C'est ici que les namespaces ont leur utilités, ils permettent de trier, différenciers, catégoriser les classes.
On peut les imaginer un peu comme des dossiers et sous-dossier où sont rangé les classes.
namespace HTML\Formulaire;
class Form{
// code de la class.
}
En faisant ainsi, vous indiquez que tout le code qui suis fera parti de l'espace de nom "HTML\Formulaire".
Attention, le mot clef "namespace" doit apparaître avant tout autre code.
$form = new HTML\Formulaire\Form();
namespace HTML\Formulaire;
$form = new Form();
use HTML\Formulaire\Form;
$form = new Form();
Ensuite pour utiliser votre class, vous devrez préciser son espace de nom par l'une des façons
ci-dessus.
Attention, si vous utiliser l'autoloader montré dans la section précédente il vous faudra au choix :
- Modifier l'autoloader pour qu'il gère les espaces de nom.
- Placer vos classes dans des sous dossiers correspondant à votre namespace.
Attention, si vous utiliser des class par défaut de PHP alors que vous travaillez dans un namespace, il vous faudra
leur appliquer une petite modification sous la forme de "\".
Par exemple "new \PDO();"
Info bonus
Il est possible de raccourcir l'utilisation d'un objet lorsque l'on utilise des méthodes
qui n'ont pas besoin de "return".
En donnant à ces fonctions un "return $this;", il est possible d'utiliser directement un "->methode()" sans
rappeler le nom de l'objet. voir ci dessous.