L'Autoload de PHP (avec ou sans namespace)
Posté : 21 août 2010, 19:05
PHP depuis sa version 5 comprend l'Auto-chargement de classes, ce qui veux dire que lorsque que l'on va instancier une classe il va allé la chercher seul (plus ou moins), finis les include et require multiple.
On réalise ceci grâce la fonction __autoload, on verra ensuite tout la puissance de la chose avec les fontions spl_autoload*.
Exemple 1 :
Au moment de new Test(), comme php ne trouve pas la classe il fera appelle a la fonction __autoload et lui donne en paramètre le non de la classe (ici : Test), la fonction fait tout simplement un require_once vers le fichier .php.
Si on fais $test2 = new Test2(); php ira bien-sur cherche le fichier Test2.php, ainsi que toutes les autres classes qui ne sont pas définie.
La limitation ici sera arborescence
_______________________________________________
Il y'a une autre astuce pour ça que l'on vois dans de nombreux frameworks c'est l'utilisation du underscore
Exemple 2 :
La même chose que dans l'exemple 1, sauf qui va allé chercher le fichier dans le dossier My/Framework, on peux très bien allé chercher une classe nommée My_Framwork_Utils_Debug il ira chercher My/Framwork/Utils/Debug.php
La limitation ici c'est que ca peux vite devenir lourd avec des noms a rallonge
_______________________________________________
La puissance des namespaces :
Depuis PHP 5.3 on le droit au namespace, on se rapproche donc du java, c++, as3 (et plein d'autre).
Il y'a 2 façons (+1 variante) d'appeler une classe qui appartient a un namespace
façon 1
- les noms sont vite a rallonge
- lorsque qu'on est dans un namespace toutes les classes du global changent en \Class (ex : new \DOMDocument)
façon 2
- définition des toutes les classes utilisées dans l'entête (comme en java,as3 avec import)
façon 2 (variante)
Je recommande la façon 2, c'est celle qui va le plus se rapprocher d'autres langages et le script sera plus facile a maintenir (si vous changez de namespace on changera juste dans l'en-tete les use), et pas besoin de modifier les classes global (new DOMDomcument() en new \DOMDocument)
_______________________________________________
Autoload + namespace
Voyons ce que ca donne avec les namespaces
Exemple 3 :
La même chose que dans l'exemple 2, sauf qu'il remplace les \ du namespace par le DIRECTORY_SEPARATOR (ce qui change rien sous windows)
On peux faire aussi
_______________________________________________
La méthode ultime : namespace + spl_autoload (PHP 5.3.3+)
La library SPL a aussi c'est fonction d'autoload, qui fais un surcharge de la fonction __autoload par défaut en y ajoutant quelques fonctionnalités : la prise en charge des extensions, le directory separator.
Exemple 4
un simple spl_autoload_register suffira;
spl_autoload_register appelle par défaut spl_autoload
spl_autoload, va chercher dans le path donné ( peu importe le separator) les fichiers .php ou .inc qui correspondent (on peux régler les extensions : .class.php par ex)
Le seule limitation ici sera la version de PHP qui dois être PHP 5.3.3+ (du a un bug dans les autres versions de php 5.3 (ca ne marchait pas sous *nix)
_______________________________________________
l'autoload va bien-sur également chercher dans le included_path, et même dans les phars (mais attention dans les phars tout les noms de fichier doivent être en lowercase)
Exemple 6 :
avec un phar qui contient tout la lib , qui aurait juste en webPhar : spl_autload_register(); et pour couronné le tout qui sera dans le included_path
on fera juste
On réalise ceci grâce la fonction __autoload, on verra ensuite tout la puissance de la chose avec les fontions spl_autoload*.
Exemple 1 :
//Test.php
class Test
{
public __construct()
{
return 'hello';
}
}//index.php
function __autoload($class)
{
require_once($class . '.php');
}
$test = new Test();
echo $test;
//hello
Que fais le script ?Au moment de new Test(), comme php ne trouve pas la classe il fera appelle a la fonction __autoload et lui donne en paramètre le non de la classe (ici : Test), la fonction fait tout simplement un require_once vers le fichier .php.
Si on fais $test2 = new Test2(); php ira bien-sur cherche le fichier Test2.php, ainsi que toutes les autres classes qui ne sont pas définie.
La limitation ici sera arborescence
_______________________________________________
Il y'a une autre astuce pour ça que l'on vois dans de nombreux frameworks c'est l'utilisation du underscore
Exemple 2 :
//My/Framework/Test.php
class My_Framwork_Test
{
public __construct()
{
return 'hello';
}
}//index.php
function __autoload($class)
{
$path = str_replace('_', DIRECTORY_SEPARATOR, $class);
require_once($path . '.php');
}
$test = new My_Framwork_Test();
echo $test;
//hello
Que fais le script ?La même chose que dans l'exemple 1, sauf qui va allé chercher le fichier dans le dossier My/Framework, on peux très bien allé chercher une classe nommée My_Framwork_Utils_Debug il ira chercher My/Framwork/Utils/Debug.php
La limitation ici c'est que ca peux vite devenir lourd avec des noms a rallonge
_______________________________________________
La puissance des namespaces :
Depuis PHP 5.3 on le droit au namespace, on se rapproche donc du java, c++, as3 (et plein d'autre).
Il y'a 2 façons (+1 variante) d'appeler une classe qui appartient a un namespace
façon 1
$test = new My\Framework\Test();+ simple d'utilisation- les noms sont vite a rallonge
- lorsque qu'on est dans un namespace toutes les classes du global changent en \Class (ex : new \DOMDocument)
façon 2
use My\Framework\Test
$test = new Test();+ pas de confusion dans les namespaces- définition des toutes les classes utilisées dans l'entête (comme en java,as3 avec import)
façon 2 (variante)
use My\Framework\Test as Test
$test = new Test();+/- au cas ou 2 class aurai le même nom (ex: My\Framework\DOMDocument as DOMDocument2), ce qui serait ridicule je recommande de ne pas nommer une classe qui appartient aussi au global (allez voir du coté de get_declared_classes, y'en pas pas tant que ca en plus (150 chez moi))Je recommande la façon 2, c'est celle qui va le plus se rapprocher d'autres langages et le script sera plus facile a maintenir (si vous changez de namespace on changera juste dans l'en-tete les use), et pas besoin de modifier les classes global (new DOMDomcument() en new \DOMDocument)
_______________________________________________
Autoload + namespace
Voyons ce que ca donne avec les namespaces
Exemple 3 :
//My/Framework/Test.php
namespace My\Framework;
class Test
{
public __construct()
{
return 'hello';
}
}//index.php
function __autoload($class)
{
$path = str_replace('\\', DIRECTORY_SEPARATOR, $class);
require_once($path . '.php');
}
$test = new My\Framwork\Test();
echo $test;
//hello
Que fais le script ?La même chose que dans l'exemple 2, sauf qu'il remplace les \ du namespace par le DIRECTORY_SEPARATOR (ce qui change rien sous windows)
On peux faire aussi
use My\Framwork\Test;
$test = new Test();
echo $test;
Limitation ici : définition de la function __autoload et toujours l'utilisation du require finalement_______________________________________________
La méthode ultime : namespace + spl_autoload (PHP 5.3.3+)
La library SPL a aussi c'est fonction d'autoload, qui fais un surcharge de la fonction __autoload par défaut en y ajoutant quelques fonctionnalités : la prise en charge des extensions, le directory separator.
Exemple 4
//My/Framework/Test.php
namespace My\Framework;
class Test
{
public __construct()
{
return 'hello';
}
}spl_autload_register();
$test = new My\Framwork\Test();
echo $test;
Que fais le script ?un simple spl_autoload_register suffira;
spl_autoload_register appelle par défaut spl_autoload
spl_autoload, va chercher dans le path donné ( peu importe le separator) les fichiers .php ou .inc qui correspondent (on peux régler les extensions : .class.php par ex)
Le seule limitation ici sera la version de PHP qui dois être PHP 5.3.3+ (du a un bug dans les autres versions de php 5.3 (ca ne marchait pas sous *nix)
_______________________________________________
l'autoload va bien-sur également chercher dans le included_path, et même dans les phars (mais attention dans les phars tout les noms de fichier doivent être en lowercase)
Exemple 6 :
avec un phar qui contient tout la lib , qui aurait juste en webPhar : spl_autload_register(); et pour couronné le tout qui sera dans le included_path
on fera juste
$test = new My\Framwork\Test();
echo $test;
//hello