Статьи

Использование пространств имен и автозагрузка в плагинах WordPress, часть 4

Если это первое учебное пособие, которое вы читаете в этой серии, я настоятельно рекомендую ознакомиться с тем, что мы уже рассмотрели.

По сути, вы входите в конце шоу. На этом этапе мы заложили основу для нашего плагина, написали плагин и определили и исследовали пространства имен и автозагрузчики. Осталось только применить то, что мы узнали.

Итак, в этом уроке мы соберем все части вместе. В частности, мы собираемся вернуться к исходному коду нашего плагина, пространству имен всех соответствующих классов и написать автозагрузчик, чтобы мы могли удалить все наши операторы включения.

Я буду обсуждать все подробно, как мы работаем через код. Опять же, если это первый учебник, который вы читаете в этой серии, ознакомьтесь с тем, что мы уже рассмотрели, а затем вернитесь к этому учебнику.

К этому моменту вы должны быть знакомы с тем, как мы настроили нашу среду разработки. В качестве переподготовки, вот краткое изложение программного обеспечения, которое мы используем:

  • хотя бы PHP 5.6.20
  • веб-сервер Apache
  • сервер базы данных MySQL
  • WordPress 4.6.1
  • знание API плагинов WordPress

Вам также понадобится копия исходного кода плагина, с которым мы работаем. Вы можете взять его копию прямо здесь . Предполагая, что он установлен, активирован и у вас запущена IDE, давайте начнем.

Вспомните из предыдущего урока, я фанат того, чтобы наши пространства имен следовали за организацией файлов на диске. Если вы посмотрите на структуру каталогов нашего плагина или если вы следили за серией до сих пор, вы должны увидеть что-то вроде этого:

The directory structure of our plugin

Обратите внимание, что если вы настроили свой плагин иначе, это нормально. Ваши пространства имен, скорее всего, будут другими, но это не должно влиять на все, что рассматривается в этой серии.

Используя структуру каталогов в качестве руководства, давайте пройдемся по всем файлам PHP, которые составляют наш плагин, и определим их пространства имен. Сделать это легко: это просто вопрос использования ключевого слова пространства имен и размещения квалифицированного имени в верхней части каждого файла.

Я перечислю каждый ниже.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<?php
/**
 * The plugin bootstrap file
 *
 * This file is read by WordPress to generate the plugin information in the
 * plugin admin area.
 * the plugin, registers the activation and deactivation functions, and defines
 * a function that starts the plugin.
 *
 * @link http://.tutsplus.com/tutorials/using-namespaces-and-autoloading-in-wordpress-plugins-part-1
 * @since 0.1.0
 * @package tutsplus_namespace_demo
 *
 * @wordpress-plugin
 * Plugin Name: Tuts+ Namespace Demo
 * Plugin URI: http://.tutsplus.com/tutorials/using-namespaces-and-autoloading-in-wordpress-plugins-part-1
 * Description: Learn how to use Namespaces and Autoloading in WordPress.
 * Version: 0.2.0
 * Author: Tom McFarlin
 * Author URI: https://tommcfarlin.com/
 * License: GPL-2.0+
 * License URI: http://www.gnu.org/licenses/gpl-2.0.txt
 */
 
namespace Tutsplus_Namespace_Demo;
 
// If this file is accessed directory, then abort.
if ( ! defined( ‘WPINC’ ) ) {
    die;
}
1
2
3
4
5
6
<?php
/**
 * Represents a meta box to be displayed within the ‘Add New Post’ page.
 */
 
namespace Tutsplus_Namespace_Demo\Admin;
1
2
3
4
5
6
7
<?php
/**
 * Defines the functionality required to render the content within the Meta Box
 * to which this display belongs.
 */
 
namespace Tutsplus_Namespace_Demo\Admin;
1
2
<?php
namespace Tutsplus_Namespace_Demo\Admin\Util;
1
2
3
4
5
6
<?php
/**
 * Provides a consistent way to enqueue all administrative-related stylesheets.
 */
 
namespace Tutsplus_Namespace_Demo\Admin\Util;
1
2
3
4
5
6
7
<?php
/**
 * Reads the contents of a specified file and returns a random line from the
 * file.
 */
 
namespace Tutsplus_Namespace_Demo\Admin\Util;

Есть несколько вещей, на которые следует обратить внимание в отношении соглашений, которые я использовал выше:

  • Корневое пространство имен — Tutsplus_Namespace_Demo , которое соответствует имени каталога плагина.
  • Остальные пространства имен, такие как Tutsplus_Namespace_Demo\Admin и Tutsplus_Namespace_Demo\Admin\Util также соответствуют их соответствующим каталогам; однако имена каталогов имеют регистр (в отличие от строчных).

Наконец, если вы пытались обновить страницу или пытались перемещаться по WordPress после введения операторов пространства имен, то вы, вероятно, видите ошибку в консоли, которая выглядит примерно так:

PHP Errors when loading namespaced code

И это включает в себя следующее сообщение:

Предупреждение PHP: call_user_func_array () ожидает, что параметр 1 будет допустимым обратным вызовом, функция ‘tutsplus_namespace_demo’ не найдена или недопустимое имя функции в /Users/tommcfarlin/Dropbox/Projects/tutsplus/wp-includes/plugin.php в строке 524

Или, возможно, это показывает:

Неустранимая ошибка PHP: класс ‘Meta_Box’ не найден в /Users/tommcfarlin/Dropbox/Projects/tutsplus/wp-content/plugins/tutsplus-namespace-demo/tutsplus-namespace-demo.php в строке 48

Или вы можете увидеть любое количество других подобных сообщений об ошибках. Это нормально. Это нормально.

Но возникает вопрос: что случилось с нашим плагином? К счастью, ничего. Это ожидаемое поведение.

Первое сообщение, которое вы видите, может быть результатом другого установленного вами плагина. Я не мог воспроизвести это самостоятельно; однако, когда я деактивирую несколько других плагинов, которые я запускаю, плагин генерирует второе сообщение (это сообщение, которое я хотел продемонстрировать).

Когда вы код пространства имен, PHP ожидает, чтобы найти класс в данном пространстве имен. Концептуально вы можете думать о том, что ваши классы теперь принадлежат их собственному пакету (или подпакету) или как вы его определяете. И для того, чтобы функция могла получить доступ к классу в пакете, она должна быть осведомлена о существующих пакетах.

Именно здесь в игру вступают дополнительные функции пространства имен и автозагрузка. Поэтому, прежде чем мы попытаемся получить доступ к нашему коду через их пространства имен, давайте поработаем над автозагрузчиком.

Для написания автозагрузчика потребуется следующее:

  1. понимание PHP-функции с именем spl_autoload_register
  2. написание функции, которая будет автоматически загружать наши файлы пространства имен
  3. включая нашу собственную функцию автозагрузки

Не позволяйте имени spl_autoload_register запугивать вас. Это просто означает, что эта функция является частью «Стандартной библиотеки PHP», и именно так мы «регистрируем» функцию «автозагрузки». Говорить и писать много символов, но это просто функция, которую мы собираемся использовать, чтобы сообщить PHP, как анализировать пространства имен и имена классов и где он может найти наши файлы.

Эта функция позволяет нам писать собственный код для автозагрузки файлов, а затем подключать указанную функцию к PHP. То есть мы будем говорить PHP, где найти наши файлы и как анализировать пространства имен, имена файлов и т. Д., Чтобы они включали файлы.

Учитывая все вышесказанное, мы готовы написать автозагрузчик.

При написании автозагрузчика нужно помнить, как организованы наши файлы. То есть мы хотим знать, как сопоставить наши пространства имен с нашими каталогами.

В примере, который мы используем, все просто: пространства имен являются вариантами структуры каталогов. Это не всегда верно для других проектов; однако это еще одна причина, по которой мне нравится логически организовывать свои файлы в зависимости от их физического местоположения.

Когда PHP пытается загрузить класс, нашему автозагрузчику потребуется сделать следующее:

  1. Разделите пространство имен вверх на основе слешей.
  2. Разделите пакет и подпакеты на основе символов подчеркивания и замените их дефисами (при необходимости).
  3. Знать, как сопоставить имена классов, интерфейсы и т. Д. С именами файлов.
  4. Создайте строковое представление имени файла на основе вышеуказанной информации.
  5. Включите файл.

После того, как все эти замечания были сделаны, мы получили свою работу для нас. В каталоге плагинов создайте подкаталог с именем inc , а в каталоге inc создайте файл с именем autoload.php .

В этом файле давайте перейдем к функции, которую мы будем использовать для автозагрузки наших файлов. Это должно выглядеть примерно так:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<?php
/**
 * Dynamically loads the class attempting to be instantiated elsewhere in the
 * plugin.
 *
 * @package Tutsplus_Namespace_Demo\Inc
 */
 
spl_autoload_register( ‘tutsplus_namespace_demo_autoload’ );
 
/**
 * Dynamically loads the class attempting to be instantiated elsewhere in the
 * plugin by looking at the $class_name parameter being passed as an argument.
 *
 * The argument should be in the form: TutsPlus_Namespace_Demo\Namespace.
 * function will then break the fully-qualified class name into its pieces and
 * will then build a file to the path based on the namespace.
 *
 * The namespaces in this plugin map to the paths in the directory structure.
 *
 * @param string $class_name The fully-qualified name of the class to load.
 */
function tutsplus_namespace_demo_autoload( $class_name ) {
 
    // If the specified $class_name does not include our namespace, duck out.
    if ( false === strpos( $class_name, ‘Tutsplus_Namespace_Demo’ ) ) {
        return;
    }
 
    // More to come…
}

Очевидно, это еще ничего не делает.

Обратите внимание, что я собираюсь написать код и комментарии к коду, чтобы подробно объяснить, что мы делаем. Если вы только начинаете заниматься этим самостоятельно, написание автозагрузчика вместе с использованием пространств имен и работой с файлами может быть немного разочаровывающим. Это где отладчик и использование файлов журнала могут пригодиться.

Это выходит за рамки данного руководства, но знайте, что написание автозагрузчика — это не то, что вы можете сделать правильно с первого раза.

Давайте начнем добавлять некоторые функции, учитывая шаги, перечисленные в начале этого раздела.

Во-первых, нам нужно настроить цикл, который будет повторяться в обратном направлении по частям имени файла, которые передаются в функцию автозагрузки. Мы делаем это, потому что это упрощает создание пути к файлу для автозагрузки.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
<?php
function tutsplus_namespace_demo_autoload( $class_name ) {
 
    // If the specified $class_name does not include our namespace, duck out.
    if ( false === strpos( $class_name, ‘Tutsplus_Namespace_Demo’ ) ) {
        return;
    }
 
    // Split the class name into an array to read the namespace and class.
    $file_parts = explode( ‘\\’, $class_name );
 
    // Do a reverse loop through $file_parts to build the path to the file.
    $namespace = »;
    for ( $i = count( $file_parts ) — 1; $i > 0; $i— ) {
        // More to come…
    }
}

После этого нам нужно посмотреть на $file_parts и заменить все вхождения подчеркивания дефисом, потому что все имена наших классов и интерфейс используют подчеркивания, тогда как наши имена файлов используют дефисы.

Следующие две строки — это первые две строки внутри цикла, который мы вырезали выше:

1
2
3
4
5
<?php
 
// Read the current component of the file part.
$current = strtolower( $file_parts[ $i ] );
$current = str_ireplace( ‘_’, ‘-‘, $current );

Далее нам понадобится условие, которое делает несколько вещей.

  1. Нужно проверить, какая запись пути к имени файла мы читаем.
  2. Если мы находимся на первой записи, то мы находимся в имени файла; в противном случае мы находимся в его пространстве имен.
  3. Затем, если мы читаем первую запись, нам нужно определить, пытаемся ли мы загрузить интерфейс автоматически или загружаем класс.
  4. Если это первое, то нам нужно настроить имя интерфейса, чтобы мы загружали его правильно на основе его имени файла; в противном случае мы загрузим класс на основе значения в переменной $current .

Это читается как много, но это не должно быть ужасно сложным для чтения. Посмотрите код комментария ниже:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<?php
 
// If we’re at the first entry, then we’re at the filename.
if ( count( $file_parts ) — 1 === $i ) {
 
        /* If ‘interface’ is contained in the parts of the file name, then
     * define the $file_name differently so that it’s properly loaded.
     * Otherwise, just set the $file_name equal to that of the class
     * filename structure.
     */
    if ( strpos( strtolower( $file_parts[ count( $file_parts ) — 1 ] ), ‘interface’ ) ) {
 
        // Grab the name of the interface from its qualified name.
        $interface_name = explode( ‘_’, $file_parts[ count( $file_parts ) — 1 ] );
        $interface_name = $interface_name[0];
 
        $file_name = «interface-$interface_name.php»;
 
    } else {
        $file_name = «class-$current.php»;
    }
} else {
    $namespace = ‘/’ .
}

После этого пришло время создать полный путь к файлу. К счастью, это немного больше, чем простая конкатенация строк:

1
2
3
4
5
<?php
 
// Now build a path to the file using mapping to the file location.
$filepath = trailingslashit( dirname( dirname( __FILE__ ) ) . $namespace );
$filepath .= $file_name;

Наконец, нам нужно убедиться, что файл существует. Если нет, мы отобразим стандартное сообщение об ошибке WordPress:

01
02
03
04
05
06
07
08
09
10
<?php
 
// If the file exists in the specified path, then include it.
if ( file_exists( $filepath ) ) {
    include_once( $filepath );
} else {
    wp_die(
        esc_html( «The file attempting to be loaded at $filepath does not exist.» )
    );
}

И в этот момент у нас есть полный автозагрузчик (который можно получить, загрузив файлы по ссылке на боковой панели этого сообщения, так как исходный код будет немного длинным, чтобы опубликовать его здесь в руководстве).

Наконец, важно отметить, что эта конкретная функция может (или должна) быть переписана как класс. Кроме того, класс должен состоять из нескольких небольших функций, которые можно тестировать, выполнять единственную ответственность и читать более четко, чем то, что указано выше. Возможно, в бонусном уроке я расскажу, как это будет выглядеть.

Если вы посмотрите в верхней части основного файла плагина (или файла начальной загрузки, который мы его часто называли), вы заметите несколько операторов include которые выглядят так:

01
02
03
04
05
06
07
08
09
10
<?php
 
// Include the files for rendering the display.
include_once( ‘admin/class-meta-box.php’ );
include_once( ‘admin/class-meta-box-display.php’ );
include_once( ‘admin/util/class-question-reader.php’ );
 
// Include the files for loading the assets
include_once( ‘admin/util/interface-assets.php’ );
include_once( ‘admin/util/class-css-loader.php’ );

Учитывая работу, которую мы проделали до этого момента, мы можем наконец удалить эти утверждения и заменить их только одним:

1
2
3
4
<?php
 
// Include the autoloader so we can dynamically include the rest of the classes.
require_once( trailingslashit( dirname( __FILE__ ) ) . ‘inc/autoloader.php’ );

Чтобы было ясно, мы заменили его нашим автозагрузчиком. На данный момент, мы должны сделать с нашим плагином.

Теперь, когда мы распространили пространство имен в нашем коде, чтобы обеспечить логическую организацию связанных классов, и написали автозагрузчик для автоматического включения файлов на основе пространства имен каждого класса и местоположения файлов, мы должны иметь возможность запустить наш плагин и запустить его точно так же, как и он во время первой успешной итерации.

Последнее, что нам нужно сделать, — это убедиться, что мы обновили файл начальной загрузки, чтобы мы Meta_Box PHP использовать пространства имен для Meta_Box , Meta_Box_Display , Question_Reader и CSS_Loader .

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<?php
 
use Tutsplus_Namespace_Demo\Admin;
use Tutsplus_Namespace_Demo\Admin\Util;
 
// If this file is accessed directory, then abort.
if ( ! defined( ‘WPINC’ ) ) {
    die;
}
 
// Include the autoloader so we can dynamically include the rest of the classes.
require_once( trailingslashit( dirname( __FILE__ ) ) . ‘inc/autoloader.php’ );
 
add_action( ‘plugins_loaded’, ‘tutsplus_namespace_demo’ );
/**
 * Starts the plugin by initializing the meta box, its display, and then
 * sets the plugin in motion.
 */
function tutsplus_namespace_demo() {
 
    $meta_box = new Admin\Meta_Box(
        new Admin\Meta_Box_Display(
            new Util\Question_Reader()
        )
    );
 
    $css_loader = new Util\CSS_Loader();
    $css_loader->init();
 
    $meta_box->init();
}

Обратите внимание, что в приведенном выше коде мы use ключевое слово use PHP, и мы добавляем имена наших классов к их непосредственным подпакетам. Вы можете прочитать больше об использовании в руководстве, но кратко это:

Ключевое слово use должно быть объявлено в самой внешней области файла (глобальной области) или в объявлениях пространства имен. Это связано с тем, что импорт выполняется во время компиляции, а не во время выполнения, поэтому его нельзя ограничить областью действия.

С учетом вышесказанного и при условии, что все работает правильно, вы сможете перейти на страницу добавления новой записи (или редактирования сообщения ), просмотреть наше мета-поле и увидеть запрос вопроса в верхней части боковой панели:

The meta box prompting users for inspiration

Если так, то поздравляю. Вы успешно настроили свой плагин для своих пространств имен и автозагрузки. Если нет, то дважды проверьте код в соответствии с тем, что мы здесь поделились, просмотрите журналы ошибок и убедитесь, что на экране администрирования WordPress ничего необычного не появляется.

Если вы видите что-то, скорее всего, это связано с чем-то второстепенным. Просмотрите код, который мы рассмотрели, сравните его с тем, что прикреплено здесь к этому сообщению (на боковой панели вместе с большой синей кнопкой), и посмотрите, сможете ли вы сузить проблему.

На данный момент мы достигли конца нашей серии. В последних четырех уроках мы рассмотрели много вопросов:

  • Мы создали плагин, который предлагает пользователям вопросы, чтобы помочь начать их блоггинг.
  • Мы использовали функции PHP для чтения файлов из файловой системы и отображения их на дисплее.
  • Мы определили пространства имен и автозагрузку и рассмотрели, как их можно применять.
  • Мы организовали наш код и написали собственный автозагрузчик, что делает код более читабельным, организованным и менее загроможденным.

В конечном счете, многие материалы, описанные в этой серии, могут быть использованы в существующих и будущих проектах, над которыми вы можете работать.

Помните, что вы также можете найти другие продукты, связанные с WordPress, на нашем рынке. И если вы хотите узнать больше о разработке решений для WordPress, вы можете найти все мои учебные пособия и серии на странице моего профиля . Не стесняйтесь следить за мной в моем блоге или в Твиттере, поскольку я почти ежедневно обсуждаю разработку программного обеспечения в контексте WordPress.

И помните, что ссылка для загрузки окончательного исходного кода находится на боковой панели под кнопкой « Загрузить вложение» . Конечно, не стесняйтесь задавать любые вопросы в комментариях!