Page 1 sur 1

L'Autoload de PHP (avec ou sans namespace)

Posté : 21 août 2010, 19:05
par stealth35
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 :
//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

Re: L'Autoload de PHP (avec ou sans namespace)

Posté : 06 sept. 2010, 12:46
par Gofromiel
L'autoload c'est devenu une sorte de saint Graal. Ton article est très intéressant parce qu'il rassemble les différentes techniques les plus simples pour mettre en place un tel système. C'est peut-être dommage de n'aborder que la méthode de chargement statique, simple à mettre en œuvre, mais contraignante parce qu'elle implique une arborescence stricte et surtout une seule classe par fichier (ce qui peut aussi poser des problèmes de performance).

Je vous invite à jeter un œil à ces deux articles tout aussi intéressants :

- An Auto Loader Using PHP Tokenizer, un article d'A.J. Brown, décrit un autoloader "intelligent" qui analyse les fichiers pour y découvrir les classes.

- require(), require_once() and Dynamic Autoloading in PHP un article de Paul Houle, décrit en profondeur de nombreuses méthodes avec leurs avantages et leurs inconvénients tant au niveau du développement que des performances. Il y a de nombreux liens vers de nombreuses ressources, très enrichissant.


La méthode que j'utilise personnellement est déclarative, chacun des modules de mon CMS déclare les classes qu'il utilise et leur emplacement. La plupart des déclarations se font automatiquement, et l'utilisateur peut en ajouter "à la main". Les définissions sont agrégées lorsque le framework est lancé, on se retrouve alors avec un tableau où les clés sont les noms des classes et leur valeurs leur emplacement sur le serveur. Chaque module peut aussi utiliser un dossier spécial "autoload" où l'on dépose les classes à charger automatiquement.

Parce que j'utilise un préfixe pour les classes : user_users_WdModule, user_users_WdActiveRecord..., ta méthode ne pourrais pas convenir, mais elle sera parfaitement utile pour de nombreux projets où la modularité n'est pas impérative.

Re: L'Autoload de PHP (avec ou sans namespace)

Posté : 06 sept. 2010, 18:38
par stealth35
Tout a fait d'accord avec toi, après la méthode global au niveau de php (avec l'arborescence des dossier et tout), c'est juste du copié des autres langages, l'inconvénient par rapport a ta méthode, serait que lors d'une utilisation en module, ba on utilisé toujours spl_autoload, mais de toute façon a un moment ou une autre tu dois bien faire un require* quelque part aussi.
Autre inconvénient c'est que comme tu dis on peux pas déclaré plusieurs classe dans un fichier avec cette méthode, je pense que y'a de bons benchs a faire la dessus, mais c'est quand meme la méthode la plus simple et qui a l'avantage d'être natif :wink:

Re: L'Autoload de PHP (avec ou sans namespace)

Posté : 22 sept. 2012, 23:03
par arthurart85
Bonjour.

J'essaye en vain la solution 4 celle-ci La méthode ultime : namespace + spl_autoload (PHP 5.3.3+) mais j'ai une erreur fatale.

Faut-il que la version soit absolument php5.3.3 ou peut elle être supérieure?

VOila mon erreur:


( ! ) Fatal error: spl_autoload(): Class test\aNotherClass could not be loaded in C:\wamp\www\root\test\test.php on line 4
Call Stack
# Time Memory Function Location
1 0.0007 245560 {main}( ) ..\test.php:0


et le code contenu dans le premier fichier appelé "aNotherClass.php"
namespace test;

class aNotherClass
{
    public function __construct()
    {
        echo __CLASS__;
    }
    
    public function getNameSpace()
    {
        return __NAMESPACE__;
    }
}
et celui contenu dans le deuxieme "test.php"
spl_autoload_register();

$o = new test\aNotherClass;

Re: L'Autoload de PHP (avec ou sans namespace)

Posté : 09 nov. 2012, 17:17
par Mazarini
Merci, j'ai enfin compris les namespaces.