Bonjour,

Ça fait 2 semaines que je galère avec l'auto-chargement de classes, je vous appel à l'aide.

J'ai suivi la formation "La POO en PHP", de Grafikart,
et le tutoriel "Composer", de Grafikart.
(au passage : MERCI pour les tutos, ils sont tous vraiment formidable)
Sources :
https://www.grafikart.fr/formations/programmation-objet-php
https://www.grafikart.fr/tutoriels/php/composer-480

Je rappel ici le "principe" de l'autochargement des classes, utilisé dans la formation :

// fichier : .../monSite/public/index.php
require ROOT . '/app/App.php';
App::load();

// fichier : .../monSite/app/App.php
// AUCUN NAMESPACE
use App\Config\Config;
// plein d'autres "use"
...
class App
{
    ...
    public static function load()
    {
        require ROOT . '/app/Autoloader.php';
        App\Autoloader::register();
    }
    ...
}

// fichier : .../monSite/app/Autoloader.php
namespace App;

class Autoloader
{
    static function register()
    {
        spl_autoload_register(array(__CLASS__, 'autoload'));
    }

    static function autoload($class_name)
    {
        if (strpos($class_name, __NAMESPACE__ . '\\') === 0)
        {
            $class_name = str_replace(__NAMESPACE__ . '\\', '', $class_name);
            require __DIR__ . '/' . $class_name . '.php';
        }
    }
}

Tout fonctionne très bien.

Ce que je veux

Maintenant j'aimerai charger mes classes INTERNE (je n'en suis pas encore aux dépendences),
non plus par l'autoloader de la formation,
mais par l'autoloader de Composer.

Ce que je fais

Comme le tutoriel mentionné plus haut (sur Composer), ne parle que de la gestion des dépendances, et pas de l'autochargement des classes INTERNE,
je suis allé voir ce tuto :
http://thomas.bondois.info/installer-composer-sur-un-projet-web-pour-gerer-facilement-les-libraires-externes-et-internes/
À la partie : Bonus : Utiliser l’autoloader de Composer pour tes propres librairies
On peut lire :
"Si par exemple tu utilises les namespaces, et que tes classes de base sont dans /src/Acme/ et commencent par le namespace Acme/,
tandis que celles de tests unitaires sont dans /tests/Acme/ et commencent par le namespace Test/Acme/ :"

"autoload": {
        "psr-4": {
            "Acme\\": "src/Acme/"
        }
    },
    "autoload-dev": {
        "psr-4": {
            "Tests\\Acme\\": "tests/Acme/"
        }
    }

MOI :

  • Toutes mes classes sont dans le dossier "App".
  • Et pour chacun de mes fichiers qui utilisent les namespace, le namespace commence par "App".

J'ai donc écris ce fichier composer.json :

// fichier : .../monSite/composer.json
{
    "name": "test",
    "autoload": {
        "psr-4": {
            "App\\": "App/"
        }
    }
}

puis, je n'ai pas oublié de faire un update dans la console :
composer update

ET,
j'ai commenté le chargement de l'autoloader de la formation :

// fichier : .../monSite/public/index.php
/* require ROOT . '/app/App.php';
App::load(); */

Ce que j'obtiens

Fatal error: Uncaught Error: Class 'App\Router\Router' not found in C:\xampp\htdocs\work\monSite\public\index.php:45

Sachant que dans mon index.php :

...

use App\Router\Router;
$router = new Router();    // LIGNE 45
$router->getroad();

C'est la 1ère fois que j'essaie d'utiliser Composer, et visiblement je fais n'importe quoi... :'(
Je ne me décourage pas, mais ça devient difficile.
Si vous pouviez m'aider, ce serait formidable.
(J'aimerai réussir à utiliser Composer pour charger mes classes interne).

Merci.

5 réponses


Lartak
Réponse acceptée

Bonjour.
Si tu veux utiliser l'autoloader de composer pour charger tes classes, il ne te faut pas utiliser la fonction load de ta classe App et il te faut faire un require du fichier autoload.php qui se situe dans le dossier vendor.
Et puis dans ta classe App, il te faut définir le namespace, soit namespace App;.
Par contre, je ne sais pas trop si ça peut avoir une influence ou pas, mais tu devrais respecter la casse pour le nom du dossier dans la déclaration du namespace, soit :

{
    "name": "test",
    "autoload": {
        "psr-4": {
            "App\\": "app/"
        }
    }
}

Au lieu de :

{
    "name": "test",
    "autoload": {
        "psr-4": {
            "App\\": "App/"
        }
    }
}
intelligid
Réponse acceptée

La 1ère ligne m'intrigue, pourquoi "~5.2" alors que sur le PackageList j'avais vu "v6.0.0rc2"

rc veut dire Release Candidate. C'est une version qui est susceptible de partir en release, mais encore en phase de test.

Ensuite, quand tu installes une dépendance avec Composer, pas besoin de charger un autoloader particulier, Composer se charge de tout.

Enfin, Tu as oublié le namespace \

$mail = new \PHPMailer;

De plus, pour ne recharger que l'autoloader, mieux vaut faire dump-autoload

SLK
Auteur

Ah SUPER ça fonctionne bien ça y est, merci Lartak.
Il me manquait le require du fichier autoload.php.
Bon sang, c'est comme si j'étais en apnée depuis 2 semaines et que je pouvai enfin respirer ^^

Et merci aussi intelligid pour le conseil, je ne connaissais pas dump-autoload.
Mais en fait ensuite je voulais utiliser PHPMailer, donc je vais aussi utiliser les dépendences.

D'ailleurs,
je met le sujet en résolu mais si je peux me permettre, j'ai du mal à utiliser une classe EXTERNE maintenant...

En suivant le tuto sur Composer,
je suis allé sur Packaglist,
et j'ai fais une recherche sur "PHPMailer",
parmis les choix proposés, j'ai sélectionné celui qui avait LARGEMENT le plus de download :
https://packagist.org/packages/phpmailer/phpmailer
Je vois qu'il y a :

  • composer require phpmailer/phpmailer
  • v6.0.0rc2

J'ai donc modifié mon composer.json de cette façon :

{
    "name": "test",
    "require": {
        "phpmailer/phpmailer": "v6.0.0rc2"
    },
    "autoload": {
        "psr-4": {
            "App\\": "App/"
        }
    }
}

composer update
Ça m'a créer le dossier :
.../monSite/vendor/phpmailer/phpmailer/

Toujours sur PackageList, j'ai cliqué sur le lien vers le github de PHPMailer (sur la droite).
Sur github,
https://github.com/PHPMailer/PHPMailer
je descend à la partie : A Simple Example

<?php
require 'PHPMailerAutoload.php';

$mail = new PHPMailer;
...

???
J'ai fais une recherche, aucun des fichiers dans vendor/phpmailer/phpmailer/ ne s'appelle "PHPMailerAutoload.php"

Alors toujours sur la page du github, je remonte un peu, et à la partie Installation & loading, je vois :
PHPMailer is available via Composer/Packagist (using semantic versioning), so just add this line to your composer.json file:
"phpmailer/phpmailer": "~5.2"
or
composer require phpmailer/phpmailer

La 1ère ligne m'intrigue, pourquoi "~5.2" alors que sur le PackageList j'avais vu "v6.0.0rc2",
je décide d'utiliser la 2ème méthode pour voir... (plus tard j'ai essayé la 1ère méthode, et ça donne exactement pareil)

j'écris ça dans la console :
composer require phpmailer/phpmailer
et j'update
composer update

OK j'ai toujours le dossier vendor/phpmailer/phpmailer, mais cette fois au moins, dedans j'ai : "PHPMailerAutoload.php" (OUF)

Du coup, en me RE-référant à la partie A Simple Example du github, j'écris comme code :

<?php
namespace App\Controller;

class UsersController extends AppController
{
    ...
    require ROOT . 'vendor/phpmailer/phpmailer/PHPMailerAutoload.php';
    $mail = new PHPMailer;
    ...
}

J'étais CERTAINS que ça allait fonctionner,
mais j'ai eu comme erreure :
Fatal error: Uncaught Error: Class 'App\Controller\PHPMailer' not found in C:\xampp\htdocs\work\start20\app\Controller\UsersController.php:222

la ligne 222 étant :

$mail = new PHPMailer;

Voilà donc,
PackageList, et Github, ne semblent pas donner les même instructions (je crois), et que j'essaie de suivre celles de l'un ou de l'autre, je n'arrive pas à mes fins...
Est-ce que je fais encore n'importe quoi ? :'(

SLK
Auteur

Ah d'accord !
Bon sang xD

Super, tout fonctionne et j'ai bien compris maintenant.

Merci intelligid.