Autoloading & Namespaces dans les plugins et les thèmes WordPress: ça marche?

65

Quelqu'un a-t-il déjà utilisé le chargement automatique et / ou les espaces de noms PHP dans un plugin ou un thème?

Vous pensez les utiliser? Un mal? Des pièges?

Remarque: les espaces de noms sont uniquement basés sur PHP 5.3+. Supposons, pour cette question, que vous savez que vous allez traiter avec des serveurs dont vous savez qu'ils utilisent PHP 5.3 ou une version ultérieure.

    
posée chrisguitarguy 30.08.2012 - 22:00
la source

3 réponses

85

D'accord, j'ai eu deux grands projets dans lesquels je maîtrisais suffisamment le serveur pour pouvoir nommer un espace de noms et utiliser le chargement automatique.

Première place. Le chargement automatique est génial. Ne pas s'inquiéter des besoins est une chose relativement bonne.

Voici un chargeur que j'ai utilisé pour quelques projets. Vérifie que la classe est d'abord dans l'espace de noms actuel, puis échoue si ce n'est pas le cas. A partir de là, il ne vous reste plus qu'à manipuler les chaînes pour trouver la classe.

<?php
spl_autoload_register(__NAMESPACE__ . '\autoload');
function autoload($cls)
{
    $cls = ltrim($cls, '\');
    if(strpos($cls, __NAMESPACE__) !== 0)
        return;

    $cls = str_replace(__NAMESPACE__, '', $cls);

    $path = PLUGIN_PATH_PATH . 'inc' . 
        str_replace('\', DIRECTORY_SEPARATOR, $cls) . '.php';

    require_once($path);
}

On pourrait facilement adapter cela à une utilisation sans espaces de noms. En supposant que vous préfixez les classes de votre plugin / theme de manière uniforme, vous pouvez simplement tester ce préfixe. Utilisez ensuite des traits de soulignement dans le nom de la classe comme espaces réservés pour les séparateurs de répertoires. Si vous utilisez beaucoup de classes, vous voudrez probablement utiliser une sorte d'autoloader de classmap.

Espaces de nommage et crochets

Le système d'accrochage

de WordPress fonctionne en utilisant call_user_func (et call_user_func_array ), qui prend les noms de fonction sous forme de chaînes et les appelle à l’appel de la fonction do_action (puis de call_user_func ).

Avec les espaces de noms, cela signifie que vous devez passer des noms de fonction complets incluant l’espace de noms à des points d'ancrage.

<?php
namespace WPSE\SomeNameSpace;

add_filter('some_filter', 'WPSE\SomeNameSpace\the_function');
function the_function()
{
   return 'did stuff';
}

Il serait probablement préférable de faire un usage libéral de la constante magique __NAMESPACE__ si vous souhaitez le faire.

<?php
namespace WPSE\SomeNameSpace;

add_filter('some_filter', __NAMESPACE__ . '\the_function');
function the_function()
{
   return 'did stuff';
}

Si vous mettez toujours vos crochets dans les classes, c'est plus facile. L'instance standard de création d'une classe et tous les points d'ancrage du constructeur avec $this fonctionnent correctement.

<?php
namespace WPSE\SomeNameSpace;

new Plugin;

class Plugin
{
    function __construct()
    {
        add_action('plugins_loaded', array($this, 'loaded'));
    }

    function loaded()
    {
        // this works!
    }
}

Si vous utilisez des méthodes statiques comme je le souhaite, vous devrez passer le nom de classe complet en tant que premier argument du tableau. C'est beaucoup de travail, vous pouvez donc utiliser la magie __CLASS__ constante ou get_class .

<?php
namespace WPSE\SomeNameSpace;

Plugin::init();

class Plugin
{
    public static function init()
    {
        add_action('plugins_loaded', array(__CLASS__, 'loaded'));
        // OR: add_action('plugins_loaded', array(get_class(), 'loaded'));
    }

    public static function loaded()
    {
        // this works!
    }
}

Utilisation des classes de base

La résolution du nom de classe de PHP est un peu négligée. Si vous envisagez d’utiliser des classes WP principales ( WP_Widget dans l’exemple ci-dessous), vous devez fournir des instructions use .

use \WP_Widget;

class MyWidget extends WP_Widget
{
   // ...
}

Ou vous pouvez utiliser le nom de classe complet - en le préfixant simplement par une barre oblique inverse.

<?php
namespace WPSE\SomeNameSpace;

class MyWidget extends \WP_Widget
{
   // ...
}

définit

Ceci est un code PHP plus général, mais il m’a mordu, alors le voici.

Vous pouvez définir des éléments que vous utiliserez souvent, tels que le chemin d'accès à votre plugin. L'utilisation de l'instruction define place les éléments dans l'espace de noms racine, à moins que vous ne le transmettiez explicitement au premier argument de define.

<?php
namespace WPSE\SomeNameSpace;

// root namespace
define('WPSE_63668_PATH', plugin_dir_path(__FILE__));

// in the current namespace
define(__NAMESPACE__ . '\PATH', plugin_dir_path(__FILE__));

Vous pouvez également utiliser le mot clé const dans la racine d'un fichier avec PHP 5.3 plus. consts s sont toujours dans l’espace de nom actuel, mais sont moins flexibles qu’un appel define .

<?php
namespace WPSE\SomeNameSpace;

// in the current namespace
const MY_CONST = 1;

// this won't work!
const MY_PATH = plugin_dir_path(__FILE__);

N'hésitez pas à ajouter d'autres conseils utiles!

    
réponse donnée chrisguitarguy 28.08.2013 - 23:17
la source
11

Voici une réponse pour 2017.

Le chargement automatique est génial. Namespacing est génial.

Bien que vous puissiez le faire vous-même, en 2017, il est logique d'utiliser le magnifique et omniprésent Composer pour répondre à vos besoins en PHP. Composer prend en charge les PSR-0 et PSR-4 à chargement automatique, mais le premier est obsolète depuis 2014, utilisez donc PSR-4. Cela réduit la complexité de vos répertoires.

Nous conservons chacun de nos plugins / thèmes dans son propre référentiel Github, chacun avec son propre fichier composer.json et son propre fichier composer.lock .

Voici la structure de répertoires que nous utilisons pour nos plugins. (Nous n'avons pas vraiment de plugin appelé awesome-plugin , mais nous devrions le faire.)

plugins/awesome-plugin/bootstrap.php
plugins/awesome-plugin/composer.json
plugins/awesome-plugin/composer.lock
plugins/awesome-plugin/awesome-plugin.php
plugins/awesome-plugin/src/*

plugins/awesome-plugin/vendor/autoload.php
plugins/awesome-plugin/vendor/*

Si vous fournissez un fichier composer.json approprié, Composer gère ici l'espacement des noms et le chargement automatique.

{
    "name": "awesome-company/awesome-plugin",
    "description": "Wordpress plugin for AwesomeCompany website, providing awesome functionality.",
    "type": "wordpress-plugin",
    "autoload": {
        "psr-4": {
            "AwesomeCompany\Plugins\AwesomePlugin\": "src"
        }
    }
}

Lorsque vous exécutez composer install , il crée le répertoire vendor et le fichier vendor/autoload.php , qui chargeront automatiquement tous vos fichiers avec un nom d'espacement dans src/ , ainsi que toute autre bibliothèque dont vous pourriez avoir besoin.

Ensuite, en haut de votre fichier de plugin principal (qui est pour nous awesome-plugin.php ), après les métadonnées de votre plugin, vous avez simplement besoin de:

// Composer autoloading.
require_once __DIR__ . '/vendor/autoload.php';

...

Bonus

Ce n'est pas une nécessité, mais nous utilisons le Bedrock Wordpress warmplate pour utiliser Composer dès le début. Ensuite, nous pouvons utiliser Composer pour assembler les plug-ins dont nous avons besoin via Composer, y compris votre propre plug-in que vous avez écrit ci-dessus. De plus, grâce à WPackagist , vous pouvez exiger n'importe quel autre plugin de Wordpress.org (voir l'exemple de cool-theme et cool-plugin ci-dessous).

{
  "name": "awesome-company/awesome-website",
  "type": "project",
  "license": "proprietary",
  "description": "WordPress boilerplate with modern development tools, easier configuration, and an improved folder structure",
  "config": {
    "preferred-install": "dist"
  },
  "repositories": [
    {
      "type": "composer",
      "url": "https://wpackagist.org"
    },
    { // Tells Composer to look for our proprietary Awesome Plugin here.
        "url": "https://github.com/awesome-company/awesome-plugin.git",
        "type": "git"
    }
  ],
  "require": {
    "php": ">=5.5",
    "awesome-company/awesome-plugin": "dev-production", // Our plugin!
    "wpackagist-plugin/cool-plugin": "dev-trunk",       // Someone else' plugin
    "wpackagist-theme/cool-theme": "dev-trunk",         // Someone else' theme
    "composer/installers": "~1.2.0",     // Bedrock default
    "vlucas/phpdotenv": "^2.0.1",        // Bedrock default
    "johnpbloch/wordpress": "4.7.5",     // Bedrock default
    "oscarotero/env": "^1.0",            // Bedrock default
    "roots/wp-password-bcrypt": "1.0.0"  // Bedrock default
  },
  "extra": {
    // This is the magic that drops packages with the correct TYPE in the correct location. 
    "installer-paths": {
      "web/app/mu-plugins/{$name}/": ["type:wordpress-muplugin"],
      "web/app/plugins/{$name}/": ["type:wordpress-plugin"],
      "web/app/themes/{$name}/": ["type:wordpress-theme"]
    },
    "wordpress-install-dir": "web/wp"
  },
  "scripts": {
    "test": [
      "vendor/bin/phpcs"
    ]
  }
}

Remarque 1: les commentaires ne sont pas légaux en JSON, mais j'ai annoté le fichier ci-dessus pour plus de clarté.

Remarque 2: Par souci de concision, j’ai découpé quelques éléments du fichier de référence du substratum rocheux.

Note 3: C’est pourquoi le champ type du premier fichier composer.json est significatif. Le compositeur le dépose automatiquement dans le répertoire web/app/plugins .

    
réponse donnée haz 07.06.2017 - 02:34
la source
4

J'utilise l'autoloading (mon plug-in contient un grand nombre de classes, en partie parce qu'il inclut Twig), jamais un problème n'a été signalé à mon attention (plug-in installé 20 000 fois).

Si vous êtes sûr de ne jamais avoir besoin d’utiliser une installation php ne prenant pas en charge les espaces de noms, vous êtes satisfait (~ 70% des blogs WordPress actuels ne prennent pas en charge les espaces de noms). Quelques points à noter:

Il semble que je me souvienne que les espaces de noms ne sont pas sensibles à la casse dans les PHP normaux, ils le sont quand on utilise fastcgi php sur IIS - cela provoque des maux de tête si vous testez sur Linux et ne repérez pas une lettre minuscule non autorisée.

Même si vous êtes sûr que le code que vous développez actuellement ne sera utilisé que sur > 5.3.0, vous ne pourrez pas réutiliser de code avec des projets qui n’ont pas ce luxe - c’est la raison principale pour laquelle je n’ai pas utilisé d’espaces de noms dans des projets internes. J’ai constaté que les espaces de noms n’ajoutent vraiment pas cela par rapport au mal de tête possible lié à la suppression de leur dépendance.

    
réponse donnée Daniel Chatfield 03.09.2012 - 16:07
la source

Lire d'autres questions sur les étiquettes