PHP

PHP (officiellement, ce sigle est un acronyme récursif pour PHP Hypertext Preprocessor) est un langage de scripts généraliste et Open Source, spécialement conçu pour le développement d'applications web. Il peut être intégré facilement au HTML.


Que peut faire PHP ?

Tout. PHP est principalement conçu pour servir de langage de script coté serveur, ce qui fait qu'il est capable de réaliser tout ce qu'un script CGI quelconque peut faire, comme collecter des données de formulaire, générer du contenu dynamique, ou gérer des cookies. Mais PHP peut en faire bien plus.

Il y a trois domaines différents où PHP peut s'illustrer.

- Langage de script côté serveur. C'est l'utilisation la plus traditionnelle, et aussi le principal objet de PHP. Vous aurez besoin de trois composants pour l'exploiter : un analyseur PHP (CGI ou module serveur), un serveur web et un navigateur web. Vous devez exécuter le serveur web en corrélation avec PHP. Vous pouvez accéder au programme PHP avec l'aide du navigateur web. Tout ceci peut fonctionner sur votre propre machine si vous souhaitez juste expérimenter la programmation PHP. Voyez la section d'installation pour plus d'informations.

- Langage de programmation en ligne de commande. Vous pouvez écrire des scripts PHP et l'exécuter en ligne de commande, sans l'aide du serveur web et d'un navigateur. Il vous suffit de disposer de l'exécutable PHP. Cette utilisation est idéale pour les scripts qui sont exécutés régulièrement (avec un cron sous Unix ou Linux), ou un gestionnaire de tâches (sous Windows). Ces scripts peuvent aussi être utilisés pour réaliser des opérations sur des fichiers texte. Voyez la section sur l'utilisation de PHP en ligne de commande pour plus d'informations.

- Ecrire des applications clientes graphiques. PHP n'est probablement pas le meilleur langage pour écrire des applications clientes graphiques, mais si vous connaissez bien PHP et que vous souhaitez exploiter des fonctionnalités avancées dans vos applications clientes, vous pouvez utiliser PHP-GTK pour écrire de tels programmes. Vous avez aussi la possibilité d'écrire des applications très portables avec ce langage. PHP-GTK est une extension de PHP, qui n'est pas fournie dans la distribution de base.


Doc de référence : Manuel PHP


Commençons !

<?php // Le code PHP doit être encapsulé avec la balise <?php ... ?>
// Si le fichier ne contient que du php, il ne faut pas mettre la balise fermante pour éviter des accidents d'interprétation du code

// Deux slashes au début d'une ligne pour la mettre en commentaire
/*
un bloc multiligne de commentaire
*/


// () sont optionnel pour les print and echo
echo "World\n"; // Affiche uniquement "World" sur cette ligne
// (toutes les déclaration se finissent obligatoirement par un point-virgule)





/************************************
* Types & Variables
*/

// Toutes les variables commence avec le symbole $
// Quand vous assignez une valeur à une variable, PHP créé la variable avec le bon type

// Les booléens sont insensible à la casse
$boolean = true; // ou TRUE ou True

// Pour connaitre le type d'une variable, utiliser la fonction gettype ( mixed $value ) : string
echo gettype($boolean) // boolean

// Les entiers
$int1 = 12; // => 12
$int2 = -12; // => -12
$int3 = 012; // => 10 (nombre octal car commence par 0)
$int4 = 0x0F; // => 15 (hexadécimal car commence par 0x)
$int5 = 0b11111111; // => 255 (nombre binaire car commence par 0b)


// Les décimaux (floats)
$float = 1.234;
$float = 1.2e3;
$float = 7E-10;


// Supprimer une variable
unset($int1);

// Opérateurs arithmétiques
$sum = 1 + 1; // 2
$difference = 2 - 1; // 1
$product = 2 * 2; // 4
$quotient = 2 / 1; // 2


// Autres opérateurs arithmetiques
$number = 0;
$number += 1; // augmente $number de 1
echo $number++; // affiche 1 (incrémentation est fait après l'interprétation)
echo ++$number; // affiche 3 (incrémentation est fait avant l'interprétation)
$number /= $float; // divise et assigne le quotient à $number


// Les chaîne de caractère entre simple quote ne sont pas interprétés
$sgl_quotes = '$String'; // => '$String'

// Contrairement aux double quote
$dbl_quotes = "This is a $sgl_quotes."; // => 'This is a $String.'

// Les variable peuvent être entourées d'accolades
$apples = "I have {$number} apples to eat."; // I have 2 apples to eat.
$oranges = "I have ${number} oranges to eat."; // I have 2 oranges to eat.
$money = "I have $${number} in the bank."; // I have $2 in the bank.


// Heredocs
$heredoc = <<<END
Multi line
$sgl_quotes
END;


// Affiche :
Multi line
$String

// La concatenation de string se fait avec .
echo 'This string ' . 'is concatenated';

// La concaténation de chaine de caractère est exécutée plus rapidement avec des simple quotes puisque les variables ne sont pas interprétées.
// Cependant depuis PHP 7, les concaténations multiples entre doubles quotes sont plus rapides.

// Les chaîne peuvent être passées comme paramètre à écho
echo 'Multiple', 'Parameters', 'Valid'; // Retourne 'MultipleParametersValid'


/********************************
* Référence
*/

$x = 1;
$y = 2;
$x = $y; // $x contient maintenant la même valeur que $y
$z = &$y;

// $z contient maintenant une référence à $y. Changer la valeur de $z changera la valeur de $y et vice-versa.
// $x restera inchangé

echo $x; // => 2
echo $z; // => 2
$y = 0;
echo $x; // => 2
echo $z; // => 0


// Vous pouvez passer une variable par référence à une fonction, de manière à ce que celle-ci puisse la modifier.
function foo(&$var)
{
    $var++;
}
$a=5;
foo ($a);
// $a vaut 6 maintenant



/********************************
* Constantes
*/

// Une constante est définie en utilisant define() et ne peut jamais être modifiée during le temps d'exécution
define("FOO", "something");

// Accès à la constante est possible en appellant le nom de la constante sans $
echo FOO; // retourne 'something'
echo 'This outputs ' . FOO; // retourne 'This outputs something'


// Depuis PHP 7, il est possible de définir un tableau de constante
define('ANIMAUX', [
    'chien',
    'chat',
    'oiseau'
]);

echo ANIMAUX[1]; // affiche "chat"


// Appel d'une constante de classe
class foo {
    const test = 'constante';
}

echo foo::test; // => constante



/********************************
* Arrays
*/

// Tous les tableaux en PHP sont des tableaux associatifs (hashmaps dans certains langages)
$associative = array('One' => 1, 'Two' => 2, 3);

// ou
$associative = ['One' => 1, 'Two' => 2, 3];
echo $associative['One']; // affiche 1


// Ajout d'un élement à un tableau associatif
$associative['Four'] = 4;

// Les valeurs sont implicitement assigner à un clé/index numérique
$array = ['One', 'Two', 'Three'];
echo $array[0]; // => "One"


// Ajout d'un élément à la fin d'un tableau
$array[] = 'Four';
// ou
array_push($array, 'Five');

// Il est possible de concaténer deux tableaux
$data['one'] = 1;
$data += ['two' => 2, 'three' => 3];
$data += ['four' => 4]; // => ['one' => 1, 'two' => 2, 'three' => 3, 'four' => 4]


// Supprimer un élement d'un tableau
unset($array[3]);


/********************************
* Fonctions sur les tableaux
*/

// référence : https://www.php.net/manual/fr/ref.array.php
// count : Compte tous les éléments d'un tableau ou quelque chose d'un objet
$a[0] = 1;
$a[1] = 3;
$a[2] = 5;
var_dump(count($a)); // int(3)


// current : Retourne l'élément courant du tableau
$transport = array('foot', 'bike', 'car', 'plane');
$mode = current($transport); // $mode = 'foot';
$mode = next($transport); // $mode = 'bike';
$mode = current($transport); // $mode = 'bike';
$mode = prev($transport); // $mode = 'foot';
$mode = end($transport); // $mode = 'plane';
$mode = current($transport); // $mode = 'plane';


// array_unique : Dédoublonne un tableau
$input = ["a" => "green", "red", "b" => "green", "blue", "red"];
$result = array_unique($input); // [a => green, 0 => red, 1 => blue];


// array_column : Retourne les valeurs d'une colonne d'un tableau d'entrée
$records = [
    [
        'id' => 2135,
        'first_name' => 'John',
        'last_name' => 'Doe',
    ],
    [
        'id' => 3245,
        'first_name' => 'Sally',
        'last_name' => 'Smith',
    ]
];
$first_names = array_column($records, 'first_name'); // [0 => John, 1 => Sally]


// array_map : Applique une fonction sur les éléments d'un tableau
// Supprime les espaces en début et fin de chaîne avec la méthode trim sur tous les éléments d'un tableau

function execTrim($value)
{
    return trim($value);
}
$aLines = [' one', 'two '];
$aLines = array_map('execTrim', $aLines) // ['one', 'two']


// Utiliser une fonction anonyme en remplacement de la fonction execTrim
$aLines = array_map(function ($item) {
            return trim($item);
        }, $aLines); // ['one', 'two']


// Les fonctions fléchées ont été introduites en PHP 7.4 et permettent d'écrire de façon plus concise les fonctionnalités des fonctions anonymes, à l'exception que l'utilisation des variables de la portée parente est automatique.
$aLines = array_map(fn($item) => trim($item), $aLines); // ['one', 'two']


/********************************
* Logique
*/

// Initialisation
$a = 0;
$b = '0';
$c = '1';
$d = '1';


// Ces comparaisons sont toujours vraies, même si leurs types sont differents.
// Note : assert lève un warning si assertion n'est pas vraie.
assert($a == $b); // egalité
assert($c != $a); // inégalité
assert($c <> $a); // alternative à inégalité
assert($a < $c);
assert($c > $b);
assert($a <= $b);
assert($c >= $d);


// Comparaison stricte des valeurs et de leurs types.
assert($c === $d); // identique
assert($a !== $d);
assert(1 === '1'); // Warning
assert(1 !== '1');


// Operateur 'Spaceship' (depuis PHP 7)
// Returns 0 si les valeurs de chaque côté sont égales
// Returns 1 si la valeur à gauche est plus grand
// Returns -1 si la valeur à gauche est plus grand
$a = 100;
$b = 1000;

echo $a <=> $a; // 0
echo $a <=> $b; // -1 $a < $b
echo $b <=> $a; // 1 $b > $a


// Les variables peuvent être converties dans d'autres types
$string = '1';
var_dump($string + $string); // int(2)

$boolean = (boolean) 1; // => true



/********************************
* Structures de contrôle
*/

if (true) {
    // code exécuté car toujours vrai
}

if (false) {
    // code non exécuté
} else {
    // code exécuté
}

if (false) {
    // code non exécuté
} elseif (true) {
    // code exécuté
}


// Utiliser switch en remplacement d'une cascade de elseif (optimisé depuis PHP 7 et plus lisible)
switch ($variable) {
    case '0':
        print 'Switch fait de la coercition';
        break; // Vous devez inclure un "break", sinon vous tomberez dans les cas 'two' et 'three'
    case 'two':
    case 'three':
        // Faire quelque chose si $variable vaut 'two' ou 'three'
        break;
    default:
        // Faire quelque chose par défaut. Toujours déclarer un default.
}


// Il est aussi préférable d'utiliser l'opérateur ternaire
print (false ? 'Tik' : 'Tok'); // => Tok

// Ou
$sValue = 'Tik'
if (true) {
    $sValue = 'Tok'
} // => Tok


// les ternaires peuvent avoir une syntaxe encore plus condensées
$x = 'true';
var_dump($x ?: 'Does'); // => string(4) "true"


// L'opérateur Null coalescent est disponible depuis PHP 7, qui est équivalent à isset()
$_GET['utilisateur'] = null;
$identifiant = $_GET['utilisateur'] ?? 'aucun'; // => 'aucun'


// équivalent à $identifiant = isset($_GET['utilisateur']) ? $_GET['utilisateur'] : 'aucun';

// On boucle avec while, do...while
$i = 0;
while ($i < 5) {
    echo $i++;
} // Affiche "01234"

$i = 0;
do {
    echo $i++;
} while ($i < 5); // Affiche "01234"

for ($x = 0; $x < 10; $x++) {
    echo $x;
} // Affiche "0123456789"


// La boucle foreach permet de faire des itérations sur les array
$aRoues = ['vélo' => 2, 'voiture' => 4];
foreach ($aRoues as $index => $valeur) {
    echo "$index = $valeur roues ";
} // Affiche "vélo = 2 roues voiture = 4 roues"



/********************************
* Fonctions
*/

// Définir une fonction avec le mot clé "function":
function my_function () {
    return 'Hello';
}

echo my_function(); // => "Hello"

function add ($x, $y = 1) { // $y est optionnel, par défaut vaut 1
    $result = $x + $y;
    return $result;
}

echo add(4); // => 5
echo add(4, 2); // => 6

// $result n'est pas accessible en dehors de la fonction

// Depuis PHP 5.3, vous pouvez déclarer des fonctions anonymes
$increment = function ($x) {
    return $x + 1;
};

echo $increment(2); // => 3


// Les fonctions peuvent retourner des fonctions
function foo ($x, $y, $z) {
    echo "$x - $y - $z";
}

function bar ($x, $y) {
    // Utiliser "use" pour avoir des variables externes dans le scope de la fonction anonyme
    return function ($z) use ($x, $y) {
        foo($x, $y, $z);
    };
}


// Il est possible d'utiliser une syntaxe plus concise en utilisant une fonction fléchée (PHP 7.4)
function bar ($x, $y) {
    return fn($z) => foo($x, $y, $z);
}

$bar = bar('A', 'B');
$bar('C'); // Prints "A - B - C


// Vous pouvez appeller des fonctions nommées en string
$function_name = 'add';
echo $function_name(1, 2); // => 3

// Ou utiliser call_user_func(callable $callback [, $parameter [, ... ]]);

// Depuis PHP 5.6 vous pouvez passer un nombre de paramètres variables
function variable($word, ...$list) {
    echo $word . " || ";
    foreach ($list as $item) {
        echo $item . ' | ';
    }
}

variable("Separate", "Hello", "World"); // Separate || Hello | World |


// La classe générateur dont le mot clé est yield implémentent la classe Iterator.
// Il est préférable d'utiliser des générateurs que des iterateurs effectuant des return car la mémoire ne croit pas à chaque itération.
$aRoues = [' vélo' => 2, 'voiture ' => 4];

$trimData = (function() use ($aRoues) {
        foreach($aRoues as $value) {
            yield trim($value);
        }

        // Depuis PHP 5.5, il est possible de retourner une expression finale
        return 6;
})();

foreach ($trimData as $value) {
    echo $value, PHP_EOL;
}

echo $trimData->getReturn(), PHP_EOL;
// => 2
// => 4
// => 6



/********************************
* Classes
*/

// Les classes sont définis avec le mot clé "class"

class MyClass
{
    const MY_CONST = 'value'; // Une constante

    static $staticVar = 'static';

    // Variables statiques et leurs visibilités
    public static $publicStaticVar = 'publicStatic';
    // Accessible seulement dans la classe
    private static $privateStaticVar = 'privateStatic';
    // Accessible dans cette classe et ces sous-classes
    protected static $protectedStaticVar = 'protectedStatic';

    // Les attributs de classe doivent être déclarés leurs visibilités
    public $property = 'public';
    public $instanceProp;
    protected $prot = 'protected'; // Accessible dans cette classe et ces sous-classes
    private $priv = 'private'; // Accessible seulement dans la classe

    // Crée un constructeur avec __construct
    public function __construct($instanceProp)
    {
        // Attribut accessible via $this
        $this->instanceProp = $instanceProp;
    }

    // PHP 8.0 a introduit la promotion du constructeur qui fournit un raccourci pour les assignations des propriétés :
    public function __construct(protected string $instanceProp) {
    }

    // Les méthodes sont déclarées comme des fonctions à l'intérieur d'une classe
    public function myMethod()
    {
        print 'MyClass';
    }

    // Le mot clé "final" rend impossible la surcharge de la méthode et lève une erreur fatal
    final function youCannotOverrideMe()
    {
    }

    // Le mot clé "final" est utilisable pour les classes, levant une erreur fatal si la classe final est étendue.
    // Sur la branche PHP 8.1, les constantes peuvent être déclarées comme finale.

    // Les "méthodes magiques" sont des méthodes prédéfinies spéciales qui sont déclenchées automatiquement en réponse à certaines actions dans votre code.

    // Faire ça pour traiter un Object comme une String
    public function __toString()
    {
        return $property;
    }

    // Opposé à __construct()
    public function __destruct()
    {
        print "Destroying";
    }
    // Cette méthode n'a plus d'utilité à partir de PHP 5.3 qui fournit un ramasse-miettes (Garbage Collection).

    // Déclarer les attributs ou les méthodes comme static fait qu'ils sont accessibles sans avoir besoin d'instantier la classe.
    public static function myStaticMethod()
    {
        print 'I am static';
    }
}

// Les constantes de classe sont toujours accessible statiquement
echo MyClass::MY_CONST; // => 'value';

echo MyClass::$staticVar; // => 'static';
MyClass::myStaticMethod(); // => 'I am static';


// Instancier une classe avec le mot clé "new"
$my_class = new MyClass('An instance property');
// Les parenthèses sont optionnelles si aucun argument n'est passé.

// Access aux membres de la classe en utilisant ->
echo $my_class->property; // => "public"
echo $my_class->instanceProp; // => "An instance property"
$my_class->myMethod(); // => "MyClass"


// Depuis PHP 7, les déclarations de type scalaire sont possibles pour typer les arguments d'une function : les chaînes de caractères (string), les entiers (int), les décimaux (float) et les valeurs booléennes (bool).
// Ils complètent les autres types déjà existant : les noms des classes, les interfaces, les tableaux (array) et les fonctions appelables (callable).
function sommeEntiers(int ...$entiers)
{
    return array_sum($entiers);
}


// De plus depuis PHP 7, il est possible de déclarer le type du retour
function sommeTableaux(array ...$tableaux): array
{
    return array_map(function(array $tableaux): int {
        return array_sum($tableaux);
    }, $tableaux);
}



// Etendre des classes en utilisant le mot clé "extends". Vous pouvez bien-sûr étendre les classes internes de PHP
class MyOtherClass extends MyClass
{
    public function printProtectedProperty()
    {
        echo $this->prot;
    }

    // Surcharger une méthode
    public function myMethod()
    {
        parent::myMethod();
        print ' > MyOtherClass';
    }
}

$my_other_class = new MyOtherClass('Instance prop');
$my_other_class->printProtectedProperty(); // => Affiche "protected"
$my_other_class->myMethod(); // Affiche "MyClass > MyOtherClass"

final class YouCannotExtendMe {}


// Vous pouvez utiliser les "méthodes magiques" pour créer des accesseurs (getters) et des mutateurs (setters)
class MyMapClass
{
    private $property;

    public function __get($key)
    {
        return $this->$key;
    }

    public function __set($key, $value)
    {
        $this->$key = $value;

    }
}

$oClass = new MyMapClass();
echo $oClass->property; // Appel implicite à la méthode __get()
$oClass->property = 'Something'; // Appel implicite à la méthode __set()


// Les classes peuvent être abstraites (en utilisant le mot clé "abstract") ou implémenter des interfaces (en utilisant le mot clé "implements").
// Une interface est déclarée avec le mot clé "interface"
// Les interfaces vous permettent spécifier quelles méthodes d'une classe doit être implémenté, sans avoir à définir comment ces méthodes fonctionneront. Une interface = un contrat.
// Les méthodes d'une interface sont obligatoirement "public". Utiliser une classe abstraite pour pouvoir définir d'autres visibilités.
interface InterfaceOne
{
    public function doSomething();
}

interface InterfaceTwo
{
    public function doSomethingElse();
}


// Les interfaces peuvent être étendues
interface InterfaceThree extends InterfaceTwo
{
    public function doAnotherContract();
}


// Les classes abstraite ne peuvent pas être instanciées. Toutes les méthodes abstraites doivent être définies par la classe enfant, la classe qui étend la classe abstraite. Une classe abstraite = un cadre.
abstract class MyAbstractClass implements InterfaceOne
{
    public $x = 'doSomething';
}

class MyConcreteClass extends MyAbstractClass implements InterfaceTwo
{
    public function doSomething()
    {
        echo $x;
    }

    public function doSomethingElse()
    {
        echo 'doSomethingElse';
    }
}



// Les classes peuvent implémenter plus d'une interface
class SomeOtherClass implements InterfaceOne, InterfaceTwo
{
    public function doSomething()
    {
        echo 'doSomething';
    }

    public function doSomethingElse()
    {
        echo 'doSomethingElse';
    }
}



// Il faut savoir que la variable représentant un objet ne contient pas l'objet lui-même mais un id pointant vers celui-ci.
$oObjectA = new StdClass();
$oObjectA->attributeA = "test1";

$oObjectB = $oObjectA;
$oObjectB->attributeA = "test2";
var_dump($oObjectB->attributeA); // => test2
var_dump($oObjectA->attributeA); // => test2

// Donc pour copier un objet il faut utiliser le mot-clé clone
$oObjectB = clone $oObjectA;
$oObjectB->attributeA = "test2";
var_dump($oObjectB->attributeA); // => test2
var_dump($oObjectA->attributeA); // => test1


// <nom class>:class retourne le nom de complet de la classe dont le namespace. PHP 5.5.


/********************************
* Traits
*/

// Les traits sont disponibles depuis PHP 5.4 et permettent de faire de l'héritage multiple, c'est à dire d'étendre horizontalement une classe de fonctionnalités regroupée dans des traits.
trait MyTrait
{
    public function myTraitMethod()
    {
        print 'I have MyTrait';
    }
}

class MyTraitfulClass
{
    use MyTrait;
}

$cls = new MyTraitfulClass();
$cls->myTraitMethod(); // Affiche "I have MyTrait"



/********************************
* Espace de noms
*/

// La déclaration d'un espace de noms doit être la première instruction dans un fichier PHP.
// Les espaces de noms PHP fournissent un moyen pour regrouper des classes, interfaces, fonctions ou constantes.
// Par défaut, les classes existent dans l'espace de noms global et peuvent être appelées explicitement avec un backslash.
$cls = new \MyClass();

// Définir l'espace de noms dans un fichier PHP avec le mot clé "namespace"
namespace My\Namespace;

class MyClass
{
}


// Dans un autre fichier
$cls = new My\Namespace\MyClass;

// Ou depuis un autre espace de noms
namespace My\Other\Namespace;

use My\Namespace\MyClass;

$cls = new MyClass();


// Ou vous pouvez utiliser des alias d'espace de noms
namespace My\Other\Namespace;
use My\Namespace as SomeOtherNamespace;

$cls = new SomeOtherNamespace\MyClass();


// Vous pouvez récupérer une chaîne contenant le nom qualifié complet de la classe ClassName en utilisant ClassName::class
namespace App\Controller;
use App\Form\PaymentType;

PaymentType::class // => App\Form\PaymentType



/**********************
* Late Static Binding (Résolution statique à la volée)
*/

class ParentClass
{
    public static function who()
    {
        echo "I'm a " . __CLASS__ . "\n";
    }

    public static function test()
    {
        // self fait référence à la classe dans laquelle la méthode est définie
        self::who();
        // static fait référence à la classe dans laquelle la méthode a été appelée
        static::who();
    }
}

ParentClass::test();
/*
I'm a ParentClass
I'm a ParentClass
*/


class ChildClass extends ParentClass
{
    public static function who()
    {
        echo "But I'm " . __CLASS__ . "\n";
    }
}

ChildClass::test();
/*
I'm a ParentClass
But I'm ChildClass
*/



/**********************
* Constantes magiques
*/

// Obtenir le nom de la classe actuelle. Doit être utilisé dans une déclaration de classe.
echo "Current class name is " . __CLASS__;

// Obtenir le dossier du chemin complet d'un fichier
echo "Current directory is " . __DIR__;

    // Usage typique
    require __DIR__ . '/vendor/autoload.php';

// Obtenir le chemin complet d'un fichier
echo "Current file path is " . __FILE__;

// Obtenir le nom de la fonction actuelle
echo "Current function name is " . __FUNCTION__;

// Obtenir le numéro de ligne actuel
echo "Current line number is " . __LINE__;

// Récupèrer le nom de la méthode actuelle. Renvoie une valeur uniquement lorsqu'elle est utilisée dans une déclaration de trait ou d'objet.
echo "Current method is " . __METHOD__;

// Récupèrer le nom de l'espace de noms actuel
echo "Current namespace is " . __NAMESPACE__;

// Obtenir le nom du trait actuel. Renvoie une valeur uniquement lorsqu'elle est utilisée dans une déclaration de trait ou d'objet.
echo "Current trait is " . __TRAIT__;


/**********************
* Méthodes magiques
*/

// Le constructeur PHP est une méthode magique, qui si elle est utilisée (et il le faut), est appellée à chaque création d'une nouvelle instance de l'objet.
// Intéressant pour toutes les initialisations dont l'objet a besoin avant d'être utilisé.
class BaseClass {
    function __construct() {
        print "Dans le constructeur de BaseClass\n";
    }
}

class SubClass extends BaseClass {
    function __construct() {
        parent::__construct();
        print "Dans le constructeur de SubClass\n";
    }
}

$object = new SubClass();
// => Dans le constructeur de BaseClass
// => Dans le constructeur de SubClass

// Note: à la différence des autres méthodes, __construct() est exclus des règles de compatibilités des signatures usuel quand elle est étendue.

// Les surcharges magiques de propriétés sont possibles et permettent de "créer" dynamiquement des propriétés et des méthodes.
// Attention, l'interprétation PHP de la surcharge est différente de celle de la plupart des langages orientés objet.
// La surcharge, habituellement, fournit la possibilité d'avoir plusieurs méthodes portant le même nom mais avec une quantité et des types différents d'arguments.
public __set(string $name, mixed $value): void
// __set() est sollicitée lors de l'écriture de données vers des propriétés inaccessibles (protégées ou privées) ou non existante.

public __get(string $name): mixed
__get() est appelée pour lire des données depuis des propriétés inaccessibles (protégées ou privées) ou non existante.

public __isset(string $name): bool
__isset() est sollicitée lorsque isset() ou empty() sont appelées sur des propriétés inaccessibles (protégées ou privées) ou non existante.

public __unset(string $name): void
__unset() est invoquée lorsque unset() est appelée sur des propriétés inaccessibles (protégées ou privées) ou non existante.


// Exemple d'utilisation de l'accesseur et du mutateur magique :
class MyClass
{
    protected int $attributA; // PHP 7.4 : propriétés Typed 2.0
    protected ?string $attributB;

    public function __set($name, $value)
    {
        echo "Définition de '$name' à la valeur '$value'";
        if (property_exists($this, $name) === true) {
            echo " : propriété déjà défini\n";
            $this->$name = $value;
        }

        if (property_exists($this, $name) === false) {
                echo " : propriété créée dynamiquement\n";
                $this->$name = $value;
            }
    }

    public function __get($name)
    {
        echo "Récupération de '$name'\n";
        return ($this->$name) ? $this->$name : null;
    }
}

$object = new MyClass;
$object->attributB = 'exemple'; // => Définition de 'attributB' à la valeur 'exemple' : propriété déjà défini
echo $object->attributB; // => Récupération de 'attributB'
// => exemple

$object->attributC = 'exemple2'; // => Définition de 'attributB' à la valeur 'exemple2' : propriété créée dynamiquement
echo $object->attributC; // => Récupération de 'attributC'
// => exemple2

// On peut aussi citer la méthode __invoke qui permet d'appeler un objet comme une fonction
class CallableClass {
    public function __invoke($x)
    {
        var_dump($x);
    }
}

$obj = new CallableClass;
$obj(5); // => int(5)



/**********************
* Gestion d'erreurs
*/

// Une gestion simple des erreurs peut être effectuée avec le bloc try catch
try {
    // Do something
} catch (Exception $e) {
    // Handle exception
}


// Lors de l'utilisation de blocs try catch dans un environnement d'espace de noms, il faut antislasher l'exception, car les exceptions sont des classes qui existe dans l'espace de noms global.
try {
    // Do something
} catch (\Exception $e) {
    // Handle exception
}


// Exceptions personnalisées
class MyException extends Exception
{
    try {
        $condition = true;
        if ($condition) {
            throw new MyException('Something just happened');
        }
    } catch (MyException $e) {
        // Rattrape mon exception
    }
}


// La classe Exception possède des méthodes dont getMessage() qui va renvoyer le message d'erreur ou getCode() qui va renvoyer le code d'erreur défini lors du lancement de l'exception
try {
    if (empty($titre) === true) {
        throw new Exception('Impossible d\'afficher le titre. Le titre est requis.');
    }
    if (is_string($titre) === false) {
        // Exception émise quand une erreur est rencontrée durant l'exécution. Etend la classe Exception
        throw new RuntimeException('Le titre doit être une chaîne de caractères.');
    }
} catch (RuntimeException $e) {
    echo $e->getMessage();
} catch (Exception $e) {
    echo "Une exception est survenue : $e->getMessage()";
}


// Depuis PHP 7, la classe Error est disponible pour utiliser les exceptions avec certains types d'erreurs fatales. De plus une interface Throwable a été mis à disposition pour attraper à la fois des exceptions issues de la classe Exception et des exceptions issues de la classe Error.


/**********************
* Date
*/

// Déterminer la date et l'heure courante en instanciant l'objet DateTime
$oDateTimeZone = new DateTimeZone('Europe/Paris'); // Détermination du fuseau horaire
$oMaintenant = new DateTime('NOW', $oDateTimeZone);
$oMaintenant->format('d/m/Y à H:i:s'); // Le format est défini par une concaténation de caractères "libres" et de "mots clé"


// Pour instancier une date sur la base d'un formt spécifique, comme par exemple le format français (jour/mois/année)
$date = '01/06/2052';
$dateTime = DateTime::createFromFormat('d/m/Y', $date);
$dateTime->format('Y-m-d'); // => 2052-06-01


// Ajouter ou soustraire un intervalle de temps à une date
$oDate = new DateTime('now', new DateTimeZone('Europe/Paris'));
$oIntervalle = new DateInterval('P2D'); // période de deux jours
$oDate->sub($oIntervalle) // soustrait 2 jours à la date du jour
$oDate->add($oIntervalle) // ajoute 2 jours à la date jour


// Il est aussi possible de créer un objet DateInterval en calculant la difference entre deux dates
$d1 = new DateTime("2012-08-03 11:14:15.638276");
$d2 = new DateTime("2012-07-08 11:14:15.889342");
$diff = $d2->diff($d1);
print_r($diff->format('%a jours')); // => 26 jours



/**********************
* Design pattern
*/

// Les design pattern sont des moyens de conception répondant à des problématiques reccurentes que rencontrent les développeurs. Les plus courants sont :

/** Factory */

// Le pattern Factory ou fabrique en français a pour but de créer des objets, autrement dit c'est une classe qui va instancier des objets implémentant la même interface ou la même classe abstraite mais qui s'utilisent dans des contextes différents.
// L'avantage de cette classe est que les classes qui l'utilisent n'est pas responsable de l'implémentation, de la configuration associée et l'instanciation. De plus l'objet crée via une fabrique peut être injecté comme argument dans les classes clientes, diminuant le couplage entre les classes (injection de dépendances).
// L'exemple le plus courant est l'utilsation de plusieurs bases de données dans une application, par exemple une base MariaDb et PostgreSQL.

// Commençons par créer une interface qui définit les méthodes qui doivent être implémentées.
interface DatabaseInterface
{
    public function connect($params);
    public function query($query);
}

// Puis nos 2 classes qui vont implémenter cette interface, pour MariaDb :
class DatabaseMariaDb implements DatabaseInterface
{
    private $oInstancePDO = null;

    public function __construct()
    {
        $this->connect();
    }

    public function connect()
    {
        // Récupération des paramètres de connexion dans la configuration
        $this->oInstancePDO = // Intanciation
    }

    public function query($query)
    {
        // Implémentation spécifique à la base de données
    }
}


// Et la classe Fabrique :
class DatabaseFactory
{
    public static function create($db)
    {
        switch ($db) {
            case 'pgsql':
                $oBaseDeDonnees = new DatabasePgsql();
                break;
            case 'mariadb':
                $oBaseDeDonnees = new DatabaseMariaDb();
                break;
            default:
                throw new Exception('Unknown database');
        }

        return $oBaseDeDonnees;
    }
}


// Utilisation de la factory dans une application :
$oBaseDeDonnees = DatabaseFactory:create('mariadb');


/** Injection de dépendances */

// Design pattern spécifique à la POO (Programmation Oriénté Objet) qui est devenu une norme de développement car tous les framework moderne l'implémentent.
// L'injection de dépendance résoud le problème du couplage fort entre les classes, ce qui a comme conséquence une meilleure maintenabilité.
// Un petit exemple : Ci-dessous une classe Adresse
class Adresse
{
    private $sAdresse1;
    private $sAdresse2;
    private $sAdresse3;
    private $sAdresse4;

    public function __construct($sAdresse1, $sAdresse2, $sAdresse3, $sAdresse4)
    {
        $this->sAdresse1 = $sAdresse1;
        $this->sAdresse2 = $sAdresse2;
        $this->sAdresse3 = $sAdresse3;
        $this->sAdresse4 = $sAdresse4;
    }
}

// Et une classe Personne qui instancie la classe Adresse
class Personne
{
    private $oAdresse = null;

    public function __construct($sAdresse1, $sAdresse2, $sAdresse3, $sAdresse4)
    {
        $this->oAdresse = new Adresse($sAdresse1, $sAdresse2, $sAdresse3, $sAdresse4);
    }
}

$oPersonne = new Personne('sAdresse1', 'sAdresse2', 'sAdresse3', 'sAdresse4');


// Cette façon de faire fonctionne parfaitement, cependant instancier la classe Adresse dans la classe Personne couple fortement ces deux classes.
// En effet, si on fait évoluer la classe Adresse, en ajoutant une nouvelle ligne d'adresse, il faut aussi faire évoluer la classe Personne en ajoutant un nouveau paramètre.
// Donc pour résoudre ce problème, il faut injecter directement en paramétre une instance de la classe Adresse, c'est le design pattern injection de dépendances.
class Personne
{
    private $oAdresse = null;

    public function __construct(Adresse $oAdresse)
    {
        $this->oAdresse = $oAdresse;
    }
}


// Et plein d'autres ...