Автозавантаження та простори імен у WordPress плагіни та теми: чи може це працювати?


70

Хтось використовував автозавантаження та / або PHP-простори імен у плагіні чи темі?

Думки про їх використання? Будь-яка шкода? Підводні камені?

Примітка: простори імен мають лише PHP 5.3+. Припустимо, для цього питання, що ви знаєте, що ви матимете справу з серверами, які, на вашу думку, мають PHP 5.3 або вище.

Відповіді:


89

Гаразд, у мене було два великих проекти, де я контролював сервер достатньо, щоб простору імен і покладався на автозавантаження.

Спочатку вгору. Автозавантаження - приголомшливе. Не турбуватися про потреби - це відносно гарна річ.

Ось завантажувач, який я використовував у кількох проектах. Перевіряє, чи спочатку клас перебуває у поточному просторі імен, а потім, якщо ні. Звідти це лише якась струнна маніпуляція для пошуку класу.

<?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);
}

Можна легко адаптувати це для використання без просторів імен. Якщо припустити, що ви маєте префікс класів додатка / теми рівномірно, ви можете просто перевірити цей префікс. Потім використовуйте підкреслення в імені класу для заповнювачів роздільників каталогів. Якщо ви використовуєте багато класів, ви, швидше за все, захочете скористатися якоюсь автозавантажувачем класу.

Простори імен та гачки

Система гачків WordPress працює за допомогою call_user_funccall_user_func_array), яка приймає назви функцій як рядки і викликає їх у момент, коли do_action(і, згодом, call_user_func) виклик функції.

Що стосується просторів імен, це означає, що вам потрібно буде передати цілком кваліфіковані імена функцій, що містять простір імен, на гачки.

<?php
namespace WPSE\SomeNameSpace;

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

Можливо, було б краще скористатися __NAMESPACE__магічною постійною ліберальною, якщо ви хочете це зробити.

<?php
namespace WPSE\SomeNameSpace;

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

Якщо ви завжди кладете гачки на заняття, це простіше. Стандарт створює екземпляр класу та всі гачки в конструкторі $this.

<?php
namespace WPSE\SomeNameSpace;

new Plugin;

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

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

Якщо ви використовуєте статичні методи, як я хочу це зробити, вам потрібно буде передати повністю кваліфіковане ім’я класу як перший аргумент масиву. Це дуже багато роботи, так що ви можете просто використовувати чарівну __CLASS__константу або 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!
    }
}

Використання основних класів

Роздільна здатність назви PHP трохи вибаглива. Якщо ви збираєтесь використовувати основні класи WP ( WP_Widgetу прикладі нижче), ви повинні надати useоператори.

use \WP_Widget;

class MyWidget extends WP_Widget
{
   // ...
}

Або ви можете використовувати повністю кваліфіковане ім’я класу - в основному це лише префіксація за допомогою нахилу.

<?php
namespace WPSE\SomeNameSpace;

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

Визначає

Це більш загальний PHP, але це мене покусало, так ось воно.

Ви можете визначити речі, якими ви будете користуватися часто, наприклад шлях до вашого плагіна. Використання оператора define вводить речі в кореневу область імен, якщо ви явно не передаєте простір імен в перший аргумент 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__));

Ви також можете використовувати constключове слово на кореневому рівні файлу з PHP 5.3 плюс. constss завжди в поточному просторі імен, але менш гнучкі, ніж defineвиклик.

<?php
namespace WPSE\SomeNameSpace;

// in the current namespace
const MY_CONST = 1;

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

Будь ласка, не соромтесь додавати будь-які інші поради, які можуть бути у вас!


16

Ось відповідь 2017 року

Автозавантаження - приголомшливе. Розміщення імен - приголомшливе.

Хоча ви можете їх згорнути самостійно, але в 2017 році має сенс використовувати чудового та всюдисущого композитора для обробки ваших потреб PHP. Композитор підтримує як PSR-0, так і PSR-4 автоматичне завантаження, але перший був застарілим з 2014 року, тому використовуйте PSR-4. Це зменшує складність ваших каталогів.

Ми зберігаємо кожен із наших плагінів / тем у власному сховищі Github, у кожному зі своїм composer.jsonфайлом та composer.lockфайлом.

Ось структура каталогів, яку ми використовуємо для своїх плагінів. (Плагін насправді не називається awesome-plugin, але нам слід.)

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/*

Якщо ви надаєте відповідний composer.jsonфайл, Composer тут обробляє простір між іменами та автоматично завантажує.

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

Під час запуску composer installвін створює vendorкаталог і vendor/autoload.phpфайл, який автоматично завантажить усі ваші файли, розміщені на ім’я src/, та будь-які інші бібліотеки, які можуть знадобитися.

Потім у верхній частині вашого основного файла плагіна (який для нас є awesome-plugin.php) після метаданих вашого плагіна вам просто потрібно:

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

...

Бонусна функція

Це не обов'язково, але ми використовуємо котло Bedrock Wordpress, щоб використовувати Composer з самого початку. Тоді ми можемо використовувати Composer для збирання потрібних плагінів через Composer, включаючи ваш власний плагін, про який ви писали вище. Крім того, завдяки WPackagist , ви можете вимагати будь-якого іншого плагіна з Wordpress.org (див. Приклад cool-themeта cool-pluginнижче).

{
  "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"
    ]
  }
}

Примітка 1: коментарі не є законними в JSON, але я зазначив вищезазначений файл для більшої ясності.

Примітка 2: Я нарізав кілька шматочків файлу Bedrock для котла для стислості.

Примітка 3. Ось чому typeполе в першому composer.jsonфайлі є важливим. Композитор автоматично відкидає його в web/app/pluginsкаталог.


Вдячний за вашу відповідь, дуже корисно! Але мені цікаво "bootstrap.php", про яке ви посилаєтесь. Що він містить? :)
INT

1
Файл bootstrap.php - це стилістична річ, яку я роблю в більшості моїх проектів, в рамках WP або поза нею. Мій завантажувач зазвичай просто перевіряє параметри та змінні середовища; його головна мета - переконатися, що мій плагін завжди має те, що йому потрібно запустити, незалежно від того, запускається він у межах WP або як окремий додаток PHP.
хаз

4

Я використовую автоматичне завантаження (оскільки мій плагін містить навантаження класів - почасти тому, що він включає Twig), ніколи не було мені до уваги проблему (плагін встановлено> 20 000 разів).

Якщо ви впевнені, що вам ніколи не доведеться використовувати інсталяцію php, яка не підтримує простори імен, тоді ви знову добре (~ 70% поточних блогів Wordpress не підтримують простори імен). Кілька речей, які слід зазначити:

Я, мабуть, пам’ятаю, що простори імен не відрізняються від регістру у звичайному php, але вони використовують швидкі php в iis - це спричиняє певні головні болі, якщо ви перевіряєте на Linux і не помічаєте негідних малих літер.

Крім того, навіть якщо ви впевнені, що код, який ви зараз розробляєте, буде використовуватися лише на> 5.3.0, ви не зможете повторно використовувати будь-який код з проектами, які не мають такої розкоші - це головна причина, чому я цього не зробив використовувані простори імен у внутрішніх проектах. Я виявив, що простори імен насправді не так багато додають , якщо порівнювати з можливим головним болем необхідності зняти залежність від них.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.