web-dev-qa-db-fra.com

Problèmes liés au chargement automatique des classes via sp_autoload_register/interférant éventuellement avec l'autoloader spécifique à WP

Je travaille sur un plugin dans lequel je fais les choses suivantes pour les classes à chargement automatique:

function TFSLAutoload($class) {
    $classfile = dirname(__FILE__).'/includes/'.strtolower($class).'.php';
    include $classfile;
} // function TFSLAutoload
spl_autoload_register('TFSLAutoload');

Dans le plugin (classes), je peux instancier des classes (par exemple, utiliser $myClassXYZ = new MyClassXYZ();) ainsi que des fonctions statiques (par exemple, MyClassXYZ::my_static_func();) sans inclure/exiger le fichier définissant la classe même. En bref, tout fonctionne comme prévu.

Cependant, lorsque WP_DEBUG est défini sur true, les avertissements suivants sont générés:

Warning: include(/var/www/vhosts/MY-DOMAIN.TLD/wp-content/plugins/tf-song-list/includes/wp_atom_server.php): failed to open stream: No such file or directory in /var/www/vhosts/MY-DOMAIN.TLD/wp-content/plugins/tf-song-list/tf-song-list.php on line 31 
Warning: include(): Failed opening '/var/www/vhosts/MY-DOMAIN.TLD/wp-content/plugins/tf-song-list/includes/wp_atom_server.php' for inclusion (include_path='.:') in /var/www/vhosts/MY-DOMAIN.TLD/wp-content/plugins/tf-song-list/tf-song-list.php on line 31 
Warning: include(/var/www/vhosts/MY-DOMAIN.TLD/wp-content/plugins/tf-song-list/includes/Recursive_ArrayAccess.php): failed to open stream: No such file or directory in /var/www/vhosts/MY-DOMAIN.TLD/wp-content/plugins/tf-song-list/tf-song-list.php on line 31 
Warning: include(): Failed opening '/var/www/vhosts/MY-DOMAIN.TLD/wp-content/plugins/tf-song-list/includes/Recursive_ArrayAccess.php' for inclusion (include_path='.:') in /var/www/vhosts/MY-DOMAIN.TLD/wp-content/plugins/tf-song-list/tf-song-list.php on line 31
Warning: include(/var/www/vhosts/MY-DOMAIN.TLD/wp-content/plugins/tf-song-list/includes/WP_Session.php): failed to open stream: No such file or directory in /var/www/vhosts/MY-DOMAIN.TLD/wp-content/plugins/tf-song-list/tf-song-list.php on line 31 
Warning: include(): Failed opening '/var/www/vhosts/MY-DOMAIN.TLD/wp-content/plugins/tf-song-list/includes/WP_Session.php' for inclusion (include_path='.:') in /var/www/vhosts/MY-DOMAIN.TLD/wp-content/plugins/tf-song-list/tf-song-list.php on line 31

J'ai ensuite changé ma fonction de chargement automatique pour vérifier d'abord si le fichier existe:

function TFSLAutoload($class) {
    $classfile = dirname(__FILE__).'/includes/'.strtolower($class).'.php';
    if (file_exists($classfile)) include $classfile;
    else echo "File »$classfile« does not exist.".PHP_EOL;
} // function TFSLAutoload
spl_autoload_register('TFSLAutoload');

Maintenant, seuls mes propres fichiers de classe de plug-in sont chargés par l'autochargeur, car ce sont les seuls fichiers situés dans le dossier prédéfini.

Toutefois, si les trois classes WordPress mentionnées sont toujours "envoyées" par le biais de ma classe autolaoder, sont-elles même (finalement) chargées correctement par WP? Ou mon autochargeur est-il en concurrence avec l'autoloader intégré de WP? Comment puis-je vérifier ça? Ou est-ce que je fais tout le chargement automatique de la mauvaise façon?

Et pourquoi ces trois classes sont-elles envoyées à mon autochargeur? Sont-ils les seuls à être chargés une fois les plugins chargés?

5
tfrommen

Il n'y a pas d'autoloader intégré dans WordPress. Mais d'autres plugins ou un thème ont peut-être enregistré un autochargeur et, selon l'ordre d'exécution, ils sont appelés plus tôt ou plus tard que le vôtre.


Mise à jour 21. 08. 2014 Cette réponse n'est plus ce que je recommanderais. Utilisez un chargeur automatique si vous en avez besoin.


La seule façon de s’assurer que la classe appelée appartient bien à votre code est de vérifier avec file_exists() et de tester le nom de la classe.

file_exists() est lent et son résultat est mis en cache par le système de fichiers, vous ne pouvez donc pas vous en fier.

Je recommande de ne pas utiliser d'autoloader . Utilisez plutôt un chargeur de classes spécifique au plugin.

Exemple:

/**
 * Load a class from /php/ directory.
 *
 * There is no file_exists() check to improve performance.
 *
 * @param  string  $class         Class name
 * @param  boolean $create_object Return an object or TRUE
 * @return bool|$class
 */
function t5_es_load_class( $class, $create_object = FALSE )
{
    // create the path base just once
    static $base = FALSE;

    ! $base && $base = plugin_dir_path( __FILE__ ) . 'php';
    ! class_exists( $class ) && require "$base/class.$class.php";

    return $create_object ? new $class : TRUE;
}

Maintenant, vous pouvez utiliser cette fonction pour inclure simplement la classe…

t5_es_load_class( 'T5_Metabox_Base' );
$metabox = new T5_Metabox_Base( 'preview' );

… Ou créer un objet…

$data               = t5_es_load_class( 'T5_Property_List', TRUE );
$data->plugin_url   = plugin_dir_url( __FILE__ );
$data->plugin_path  = plugin_dir_path( __FILE__ );

Plus rapide, plus fiable, plus flexible.

4
fuxia

Si vous avez un espace de noms unique pour vos classes, cela fonctionne. J'utilise ce schéma:

  1. Farcissez toutes vos classes dans un espace de noms, disons myplugin (vous pouvez bien sûr avoir d'autres espaces de noms, comme myplugin\otherstuff\...

  2. Créez un autochargeur qui charge les classes uniquement dans cet espace de noms , vous pouvez l'utiliser, mettez-le au-dessus de votre fichier de plug-in:

    define("MYPLUGIN_DIR", plugin_dir_path(__FILE__));
    
    // Notice strlen(...) calls should be written as number for speed
    spl_autoload_register(function ($className) {           
        // Make sure the class included is in this plugins namespace
        if (substr($className, 0, strlen("myplugin\\")) === "myplugin\\") {
            // Remove myplugin namespace from the className
            // Replace \ with / which works as directory separator for further namespaces
            $classNameShort = str_replace("\\", "/", substr($className, strlen("myplugin\\")));
            include_once MYPLUGIN_DIR . "classes/$classNameShort.php";
        }
    });
    

Ça y est, cela fonctionne très bien pour plusieurs plugins si vous avez un espace de noms différent pour chacun (et vous devriez le faire quand même).

5
Ciantic

Vous pouvez utiliser un plugin WordPress Autoloader maintenant. Il prend également en charge vos propres méthodes de chargement automatique.

Veuillez consulter Page Plugin WordPress pour plus de détails.

Une utilisation correcte de PHP __autoload peut réduire considérablement le temps de chargement du site WP.

Un exemple de votre propre fonction __autoload est problématique. Vous devriez avoir une validation de tri, pour vous assurer de ne charger que vos propres classes, pour éviter les problèmes.

Veuillez noter que si vous chargez des classes, il est recommandé d'utiliser require_once ou i

0
D.A.H