Как использовать автозагрузку и плагин контейнер в WordPress плагины

Строительство и поддержание плагинWordPress может быть сложной задачей. Чем больше кодовая база, тем труднее отслеживать все рабочие части и их связь друг с другом. И вы можете добавить к этому ограничения, введенные при работе в устаревшной версии PHP, 5.2.

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

Начнем

Первое, что вам нужно сделать при создании плагина, чтобы дать ему уникальное имя. Имя важно, поскольку оно будет основой для всех наших уникальных идентификаторов (функция префикс, приставка класса, текстмен, приставка опции и т.д.). Название также должно быть уникальным в wordpress.org пространстве. Это не повредит, если мы сделаем имя броским. Fили наш образец плагина я выбрал имя Simplarity, играть на словах «просто» и «ясность».

Мы предположим, что у вас есть рабочая установка WordPress уже.

Структура Фолдера

Во-первых, создать каталог под названием simplarity внутри wp-контента / плагинов. Внутри него создается следующая структура:

  • simplarity.php: наш основной файл плагина
  • css/: каталог, содержащий наши стили
  • js/: каталог, содержащий файлы JavaScript
  • языки/: каталог, который будет содержать файлы перевода
  • src/: каталог, содержащий наши классы
  • просмотров/: каталог, который будет содержать наши файлы плагина представления

Основной файл плагина

Откройте основной файл плагина, simplarity.php, и добавьте заголовок информации о плагине:

<?php
/*
Plugin Name: Simplarity
description: >-
  A plugin for smashingmagazine.com
Version: 1.0.0
License: GPL-2.0+
*/

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

Автозагрузка

Автоматизация позволяет автоматически загружать классы с помощью автозагрузчика, так что вам не придется вручную включать файлы, содержащие определения класса. Например, когда вам нужно использовать класс, вам нужно сделать следующее:

require_once '/path/to/classes/class-container.php';
require_once '/path/to/classes/class-view.php';
require_once '/path/to/classes/class-settings-page.php';

$plugin = new Container();
$view = new View();
$settings_page = new SettingsPage();

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

Принятие КОНВЕНЦИи pear именования для названий классов

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

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

Это проще проиллюстрировать на примерах:

  • Класс под названием Simplarity-Plugin будет определен в файле src/Simplarity/Plugin.php.
  • Класс под названием Simplarity-SettingsPage будет определяться в src/Simplarity/SettingsPage.php.

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

Что о Стандартах кодирования WordPress для названий типа?

Как вы могли бы знать, WordPress имеет свою собственную конвенцию именования для названий классов. В нем говорится:

Названия классов должны использовать капитализированные слова, разделенные подчеркнутыми. Любые аббревиатуры должны быть все верхние случае. […] Имена файлов класса должны быть основаны на названии класса с class- предопруговым и подчеркиваемыми в названии класса заменены дефисами, например, WP_Error становитсяclass-wp-error.php

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

  • Стандарты кодирования WP не охватывают автозагрузку.
  • WP не следует собственным стандартам кодирования. Примеры: class.wp-scripts.php и SimplePie. Это понятно, так как WordPress вырос органически.
  • Совместимость позволяет легко использовать сторонние библиотеки, которые следуют конвенции PEAR именования, как Twig. И наоборот, вы можете легко портировать свой код в другие библиотеки, разделяющие ту же конвенцию.
  • Важно, чтобы ваш автозагрузчик был готов к работе в будущем. Когда WordPress решает до анте и, наконец, перейти к PHP 5.3 в качестве минимального требования, вы можете легко обновить код, чтобы быть PSR-0 или PSR-4-совместимы и воспользоваться встроенными пространствами имен вместо использования префиксов. Это большой плюс для совместимости.

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

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

Строительство нашего автозагрузчика

Откройте наш основной файл плагина и добавьте следующий код под заголовком информации о плагине:

spl_autoload_register( 'simplarity_autoloader' );
function simplarity_autoloader( $class_name ) {
  if ( false !== strpos( $class_name, 'Simplarity' ) ) {
    $classes_dir = realpath( plugin_dir_path( __FILE__ ) ) . DIRECTORY_SEPARATOR . 'src' . DIRECTORY_SEPARATOR;
    $class_file = str_replace( '_', DIRECTORY_SEPARATOR, $class_name ) . '.php';
    require_once $classes_dir . $class_file;
  }
}

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

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

spl_autoload_register( 'simplarity_autoloader' );

Далее мы определяем функцию simplarity-autoloader:

function simplarity_autoloader( $class_name ) {
  …
}

Обратите внимание, что он принимает $class_name параметр. Этот параметр содержит имя класса. Например, когда вы мгновенно класс с $plugin = new Simplarity_Plugin() помощью, $class_name будет содержать строку «SimplarityPlugin». Так как мы добавляем эту функцию в глобальном пространстве, важно, что у нас есть его префиксированные с simplarity .

Следующая строка проверяет, содержит $classname строку «Simplarity», которая является нашим верхним уровнем пространства имен:

if ( false !== strpos( $class_name, 'Simplarity' ) ) {

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

Следующая строка строит путь к каталогу, где находятся наши классы:

$classes_dir = realpath( plugin_dir_path( __FILE__ ) ) . DIRECTORY_SEPARATOR . 'src' . DIRECTORY_SEPARATOR;

Он использует WP, plugin_dir_path чтобы получить плагин корневой каталог. является FILE магической константой, которая содержит полный путь и имя файла текущего файла. является DIRECTORY_SEPARATOR предопределенной постоянной, которая содержит либо вперед слэш или backslash в зависимости от ОС вашего веб-сети сервер на. Мы также realpath используем для нормализации пути файла.

Эта строка разрешает путь к файлу определения класса:

$class_file = str_replace( '_', DIRECTORY_SEPARATOR, $class_name ) . '.php';

Он заменяет подчеркивание ( _ ) в $class_name с сепаратором каталога и придатков .php .

Наконец, эта строка создает путь файла к определению и включает файл с require_once помощью:

require_once $classes_dir . $class_file;

Ну вот! Теперь у вас есть автозагрузчик. Попрощайтесь с длинными очереди require_once заявлений.

Плагин контейнер

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

Использование нашего плагина контейнер

Вот то, что мы можем ожидать от плагина контейнера:

  • Храните глобальные параметры в одном месте

    Часто вы найдете этот код в плагинах:

    define( 'SIMPLARITY_VERSION', '1.0.0' );
    define( 'SIMPLARITY_PATH', realpath( plugin_dir_path( __FILE__ ) ) . DIRECTORY_SEPARATOR );
    define( 'SIMPLARITY_URL', plugin_dir_url( __FILE__ ) );
    

    Вместо того, чтобы делать это, мы могли бы сделать это вместо этого:

    $plugin = new Simplarity_Plugin();
    $plugin['version] = '1.0.0';
    $plugin['path'] = realpath( plugin_dir_path( __FILE__ ) ) . DIRECTORY_SEPARATOR;
    $plugin['url'] = plugin_dir_url( __FILE__ );
    

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

  • Хранение объектов в одном месте

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

    $plugin = new Simplarity_Plugin();
    /…/
    $plugin['scripts'] = new Simplarity_Scripts(); // A class that loads javascript files
    
  • Определения обслуживания

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

    $plugin['settings_page'] = function ( $plugin ) {
      return new SettingsPage( $plugin['settings_page_properties'] );
    };
    

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

    $plugin = new Plugin();
    $plugin['door_width'] = 100;
    $plugin['door_height'] = 500;
    $plugin['door_size'] = function ( $plugin ) {
      return new DoorSize( $plugin['door_width'], $plugin['door_height'] );
    };
    $plugin['door'] = function ( $plugin ) {
      return new Door( $plugin['door_size'] );
    };
    $plugin['window'] = function ( $plugin ) {
      return new Window();
    };
    $plugin['house'] = function ( $plugin ) {
      return new House( $plugin['door'], $plugin['window'] );
    };
    $house = $plugin['house'];
    

    Это примерно эквивалентно:

    $door_width = 100;
    $door_height = 500;
    $door_size = new DoorSize( $door_width, $door_height );
    $door = new Door( $door_size );
    $window = new Window();
    $house = new House( $door, $window );
    

    Всякий раз, когда мы получаем объект, как в $house = $plugin['house']; , объект создается (ленивый инициализации) и зависимости решаются автоматически.

Строительство Плагина контейнер

Начнем с создания класса плагинов-контейнеров. Мы назовем его «Simplarity-Plugin». Как диктует наша конвенция именования, мы должны создать соответствующий файл: src/Simplarity/Plugin.php.

Откройте Plugin.php и добавьте следующий код:

<?php
class Simplarity_Plugin implements ArrayAccess {
  protected $contents;

  public function __construct() {
    $this->contents = array();
  }

  public function offsetSet( $offset, $value ) {
    $this->contents[$offset] = $value;
  }

  public function offsetExists($offset) {
    return isset( $this->contents[$offset] );
  }

  public function offsetUnset($offset) {
    unset( $this->contents[$offset] );
  }

  public function offsetGet($offset) {
    if( is_callable($this->contents[$offset]) ){
      return call_user_func( $this->contents[$offset], $this );
    }
    return isset( $this->contents[$offset] ) ? $this->contents[$offset] : null;
  }

  public function run(){ 
    foreach( $this->contents as $key => $content ){ // Loop on contents
      if( is_callable($content) ){
        $content = $this[$key];
      }
      if( is_object( $content ) ){
        $reflection = new ReflectionClass( $content );
        if( $reflection->hasMethod( 'run' ) ){
          $content->run(); // Call run method on object
        }
      }
    }
  }
}

Класс реализует ArrayAccess интерфейс:

class Simplarity_Plugin implements ArrayAccess {

Это позволяет нам использовать его как массив PHP:

$plugin = new Simplarity_Plugin();
$plugin['version'] = '1.0.0'; // Simplicity is beauty

offsetSet offsetExists Функции, offsetUnset и должны offsetGet ArrayAccess быть реализованы. runФункция будет цикл через содержимое контейнера и запустить runnable объектов.

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

Пример плагина: Страница настроек

Этот плагин добавит страницу настроек под названием «Simplarity» под WordPress Админ и Настройки.

Давайте вернемся к основному файлу плагина. Откройте simplarity.php и добавьте следующий код. Добавьте это ниже кода автозагрузчика:

add_action( 'plugins_loaded', 'simplarity_init' ); // Hook initialization function
function simplarity_init() {
  $plugin = new Simplarity_Plugin(); // Create container
  $plugin['path'] = realpath( plugin_dir_path( __FILE__ ) ) . DIRECTORY_SEPARATOR;
  $plugin['url'] = plugin_dir_url( __FILE__ );
  $plugin['version'] = '1.0.0';
  $plugin['settings_page_properties'] = array( 
    'parent_slug' => 'options-general.php',
    'page_title' =>  'Simplarity',
    'menu_title' =>  'Simplarity',
    'capability' => 'manage_options',
    'menu_slug' => 'simplarity-settings',
    'option_group' => 'simplarity_option_group',
    'option_name' => 'simplarity_option_name'
  );
  $plugin['settings_page'] = new Simplarity_SettingsPage( $plugin['settings_page_properties'] );
  $plugin->run();
}

Здесь мы используем WP, add_action чтобы подключить нашу функцию simplarity_init plugins_loaded в:

add_action( 'plugins_loaded', 'simplarity_init' );

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

Функция simplarity_init содержит код инициализации нашего плагина. В начале, мы просто мгновенно наш плагин контейнер:

$plugin = new Simplarity_Plugin();

Эти строки присваивают данные глобальной конфигурации:

$plugin['path'] = realpath( plugin_dir_path( __FILE__ ) ) . DIRECTORY_SEPARATOR;
$plugin['url'] = plugin_dir_url( __FILE__ );
$plugin['version'] = '1.0.0';

Путь плагина содержит полный путь к нашему плагину, url содержит URL в нашем плагине каталога. Они пригодятся всякий раз, когда нам нужно включить файлы и активы. versionсодержит текущую версию плагина, который должен соответствовать той, которая содержится в информации о заголовке. Полезно всякий раз, когда вам нужно использовать версию в коде.

Следующий код присваивает различные данные settings_page_properties конфигурации:

$plugin['settings_page_properties'] = array(
  'parent_slug' => 'options-general.php',
  'page_title' =>  'Simplarity',
  'menu_title' =>  'Simplarity',
  'capability' => 'manage_options',
  'menu_slug' => 'simplarity-settings',
  'option_group' => 'simplarity_option_group',
  'option_name' => 'simplarity_option_name'
);

Эти данные конфигурации связаны с настройками WP API.

Следующий код мгновенно настраивает страницу настроек, проходя settings_page_properties по:

$plugin['settings_page'] = new Simplarity_SettingsPage( $plugin['settings_page_properties'] );

runМетод, где начинается самое интересное:

$plugin->run();

Он будет Simplarity_SettingsPage называться «собственный run метод.

Simplarity_SettingsPageКласс

Теперь нам нужно создать Simplarity_SettingsPage класс. Это класс, который объединяет функции API параметров.

Создайте файл под названием НастройкиPage.php в src/Simplarity/. Откройте его и добавьте следующий код:

<?php
class Simplarity_SettingsPage {
  protected $settings_page_properties;

  public function __construct( $settings_page_properties ){
    $this->settings_page_properties = $settings_page_properties;
  }

  public function run() {
    add_action( 'admin_menu', array( $this, 'add_menu_and_page' ) );
    add_action( 'admin_init', array( $this, 'register_settings' ) );
  }

  public function add_menu_and_page() { 

    add_submenu_page(
      $this->settings_page_properties['parent_slug'],
      $this->settings_page_properties['page_title'],
      $this->settings_page_properties['menu_title'], 
      $this->settings_page_properties['capability'],
      $this->settings_page_properties['menu_slug'],
      array( $this, 'render_settings_page' )
    );
  }

  public function register_settings() { 

    register_setting(
      $this->settings_page_properties['option_group'],
      $this->settings_page_properties['option_name']
    );   
  }

  public function get_settings_data(){
    return get_option( $this->settings_page_properties['option_name'], $this->get_default_settings_data() );
  }

  public function render_settings_page() {
    $option_name = $this->settings_page_properties['option_name'];
    $option_group = $this->settings_page_properties['option_group'];
    $settings_data = $this->get_settings_data();
    ?>
    <div class="wrap">
      <h2>Simplarity</h2>
      <p>This plugin is using the settings API.</p>
      <form method="post" action="options.php">
        <?php
        settings_fields( $this->plugin['settings_page_properties']['option_group']);
        ?>
        <table class="form-table">
          <tr>
              <th><label for="textbox">Textbox:</label></th>
              <td>
                <input type="text" id="textbox"
                  name="<?php echo esc_attr( $option_name."[textbox]" ); ?>"
                  value="<?php echo esc_attr( $settings_data['textbox'] ); ?>" />
              </td>
          </tr>
        </table>
        <input type="submit" name="submit" id="submit" class="button button-primary" value="Save Options">
      </form>
    </div>
    <?php
  }

  public function get_default_settings_data() {
    $defaults = array();
    $defaults['textbox'] = ’;

    return $defaults;
  }
}

Свойство класса $settings_page_properties хранит настройки, связанные с API параметров WP:

<?php
class Simplarity_SettingsPage {
  protected $settings_page_properties;

Функция конструктора принимает settings_page_properties и хранит его:

public function __construct( $settings_page_properties ){
  $this->settings_page_properties = $settings_page_properties;
}

Значения передаются из этой строки в основном файле плагина:

$plugin['settings_page'] = new Simplarity_SettingsPage( $plugin['settings_page_properties'] );

runФункция используется для запуска кода запуска:

public function run() {
  add_action( 'admin_menu', array( $this, 'add_menu_and_page' ) );
  add_action( 'admin_init', array( $this, 'register_settings' ) );
}

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

Эта строка подключает add_menu_and_page функцию к admin_menu действию:

add_action( 'admin_menu', array( $this, 'add_menu_and_page' ) );

Функция, add_submenu_page в свою add_submenu_page очередь, вызывает функцию WP, чтобы добавить ссылку в соответствии с WP Админ и Настройки:

public function add_menu_and_page() { 

  add_submenu_page(
    $this->settings_page_properties['parent_slug'],
    $this->settings_page_properties['page_title'],
    $this->settings_page_properties['menu_title'], 
    $this->settings_page_properties['capability'],
    $this->settings_page_properties['menu_slug'],
    array( $this, 'render_settings_page' )
  );

}

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

Параметры: add_submenu_page

  • parent_slug: имя пули для родительского меню
  • page_title: текст, отображаемый в <title> элементе страницы при выборе меню
  • menu_title: текст, который будет использоваться для меню
  • capability: возможность, необходимая для отображения этого меню пользователю
  • menu_slug: имя пули для обозначения этого меню (должно быть уникальным для этого меню)
  • function: функция, которая будет вызвана для вывода содержимого для этой страницы

Эта строка подключает register_settings функцию к admin_init действию:

add_action( 'admin_init', array( $this, 'register_settings' ) );

array( $this, ‘register_settings’ )означает, чтобы призвать register_settings , что указывает на наш $this SettingsPage экземпляр.

register_settingsЗатем вызывает register_setting WP, чтобы зарегистрировать настройки:

public function register_settings() { 

  register_setting(
    $this->settings_page_properties['option_group'],
    $this->settings_page_properties['option_name']
  );

}

Функция render_settings_page отвечает за визуализацию страницы:

public function render_settings_page() {
  $option_name = $this->settings_page_properties['option_name'];
  $option_group = $this->settings_page_properties['option_group'];
  $settings_data = $this->get_settings_data();
  ?>
  <div class="wrap">
    <h2>Simplarity</h2>
    <p>This plugin is using the settings API.</p>
    <form method="post" action="options.php">
      <?php
      settings_fields( $option_group );
      ?>
      <table class="form-table">
        <tr>
          <th><label for="textbox">Textbox:</label></th>
          <td>
            <input type="text" id="textbox"
              name="<?php echo esc_attr( $option_name."[textbox]" ); ?>"
              value="<?php echo esc_attr( $settings_data['textbox'] ); ?>" />
          </td>
        </tr>
      </table>
      <input type="submit" name="submit" id="submit" class="button button-primary" value="Save Options">
    </form>
  </div>
  <?php
}

Мы подключили render_settings_page ранее с помощью add_submenu_page .

Функция get_settings_data является функцией обертки get_option для:

public function get_settings_data(){
    return get_option( $this->plugin['settings_page_properties']['option_name'] );
}

Это необходимо для легкого получения данных настроек с помощью одного вызова функции.

Функция get_default_settings_data используется для предоставления нам наших собственных значений по умолчанию:

public function get_default_settings_data() {
  $defaults = array();
  $defaults['textbox'] = ’;

  return $defaults;
}

Абстрактирование класса страницы настроек

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

Давайте назовем этот класс Simplarity_WpSubPage . Идите вперед и создайте файл src/Simplarity/WpSubPage.php.

Теперь добавьте код ниже:

<?php
abstract class Simplarity_WpSubPage {
  protected $settings_page_properties;

  public function __construct( $settings_page_properties ){
    $this->settings_page_properties = $settings_page_properties;
  }

  public function run() {
    add_action( 'admin_menu', array( $this, 'add_menu_and_page' ) );
    add_action( 'admin_init', array( $this, 'register_settings' ) );
  }

  public function add_menu_and_page() { 

    add_submenu_page(
      $this->settings_page_properties['parent_slug'],
      $this->settings_page_properties['page_title'],
      $this->settings_page_properties['menu_title'],
      $this->settings_page_properties['capability'],
      $this->settings_page_properties['menu_slug'],
        array( $this, 'render_settings_page' )
    );

  }

  public function register_settings() { 

    register_setting(
      $this->settings_page_properties['option_group'],
      $this->settings_page_properties['option_name']
    );

  }

  public function get_settings_data(){
    return get_option( $this->settings_page_properties['option_name'], $this->get_default_settings_data() );
  }

  public function render_settings_page(){

  }

  public function get_default_settings_data() {
    $defaults = array();

    return $defaults;
  }
}

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

<?php
class Simplarity_SettingsPage extends Simplarity_WpSubPage {

  public function render_settings_page() {
    $option_name = $this->settings_page_properties['option_name'];
    $option_group = $this->settings_page_properties['option_group'];
    $settings_data = $this->get_settings_data();
    ?>
    <div class="wrap">
      <h2>Simplarity</h2>
      <p>This plugin is using the settings API.</p>
      <form method="post" action="options.php">
        <?php
        settings_fields( $option_group );
        ?>
        <table class="form-table">
          <tr>
              <th><label for="textbox">Textbox:</label></th>
              <td>
                  <input type="text" id="textbox"
                      name="<?php echo esc_attr( $option_name."[textbox]" ); ?>"
                      value="<?php echo esc_attr( $settings_data['textbox'] ); ?>" />
              </td>
          </tr>
        </table>
        <input type="submit" name="submit" id="submit" class="button button-primary" value="Save Options">
      </form>
    </div>
    <?php
  }

  public function get_default_settings_data() {
    $defaults = array();
    defaults['textbox'] = ’;

    return $defaults;
  }
}

Единственные функции, которые мы render_settings_page реализовали, и , которые get_default_settings_data настроены на эту страницу настроек.

Чтобы создать еще одну страницу настроек WP, вам просто нужно создать класс и Simplarity_WpSubPage расширить. И реализовать свои собственные render_settings_page и get_default_settings_data .

Определение службы

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

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

Откройте simplarity.php и добавьте эту функцию ниже кода Simplarity:

function simplarity_service_settings( $plugin ){

  $object = new Simplarity_SettingsPage( $plugin['settings_page_properties'] );
  return $object;
}

Обратите внимание, что наша функция обслуживания имеет $plugin параметр, который содержит наш плагин контейнер. Это позволяет нам получить доступ ко всем конфигурациям, объектам и службам, которые хранились в нашем плагине контейнере. Мы видим, что Simplarity_SettingsPage имеет зависимость от $plugin[‘settings_page_properties’] . Мы вводим эту зависимость Simplarity_SettingsPage сюда. Это пример инъекции зависимости. Инъекция зависимости — это практика, когда объекты проектируются таким образом, что они получают экземпляры объектов из других частей кода, а не строят их внутренне. Это улучшает разъединение кода.

Теперь давайте заменим эту строку simplarity_init в:

$plugin['settings_page'] = new Simplarity_SettingsPage( $plugin['settings_page_properties'] );

с назначением определения службы:

$plugin['settings_page'] = 'simplarity_service_settings'

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

Определение общей службы

Прямо сейчас, каждый раз, когда мы $plugin[‘settings_page’] получаем, новый экземпляр Simplarity_SettingsPage возвращается. В идеале, Simplarity_SettingsPage должны быть только мгновенно один раз, как мы используем WP крючки, которые, в свою очередь, должны быть зарегистрированы только один раз.

Для решения этой проблемы мы используем общий сервис. Общий сервис возвращает новый экземпляр объекта при первом вызове, при последующих вызовах он возвращает тот же экземпляр.

Давайте создадим общую службу с использованием статической переменной:

function simplarity_service_settings( $plugin ){
  static $object;

  if (null !== $object) {
    return $object;
  }

  $object = new Simplarity_SettingsPage( $plugin['settings_page_properties'] );
  return $object;
}

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

Ну вот.

Теперь, если вы активируете плагин, меню админа появится в настройках Admin под названием «Simplarity». Нажмите на него, и вы будете приняты на страницу настроек мы создали.

Settings Page In Action
Настройки Страница в действии

Будущее: PHP 5.3

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

Пространства имен

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

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

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

Анонимные функции

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

Вот пример закрытия:

<?php
$greet = function($name) {
  printf("Hello %srn", $name);
};

$greet('World');
$greet('PHP');

Использование именных пространств в классах

Давайте использовать пространства имен в определениях нашего класса. Откройте следующие файлы в src/Simplarity:

  • Плагин.php
  • НастройкиPage.php
  • WpSubPage.php

В каждом из этих файлов добавьте декларацию пространства имен сверху и удалите префикс «Simplarity» на именах классов:


// Plugin.php
namespace Simplarity;

class Plugin {
...

// SettingsPage.php
namespace Simplarity;

class SettingsPage extends WpSubPage {
...

// WpSubPage.php
namespace Simplarity;

abstract class WpSubPage {
...

Так как мы обновили наши имена класса мы также должны обновить наш класс мгновенности в simplarity.php. Мы делаем это, удаляя префиксы:

function simplarity_init() {
  $plugin = new Plugin();
  ...
}
...
function simplarity_service_settings( $plugin ){

  ...

  $object = new SettingsPage( $plugin['settings_page_properties'] );
  return $object;
}

По умолчанию PHP будет пытаться загрузить класс из корневого пространства имен, поэтому нам нужно рассказать ему о наших классах, созданных в пространстве имен. Мы добавляем это к верхней части simplarity.php как раз над кодом autoloader:

use SimplarityPlugin;
use SimplaritySettingsPage;

Это называется импортом/айнесингом с оператором использования.

Обновление Автозагрузчик

Откройте simplarity.php и измените эту линию в автозагрузчике от:

$class_file = str_replace( '_', DIRECTORY_SEPARATOR, $class_name ) . '.php';

Кому:

$class_file = str_replace( '', DIRECTORY_SEPARATOR, $class_name ) . '.php';

Помните, что в коде 5.2 мы используем подчеркиватели в качестве иерархии сепараторов. Для 5,3 «мы используем пространства имен, которые используют backslash «к» в качестве иерархии сепараторов. Таким образом, мы просто обмениваем «я» на «я». Мы используем еще один backslash, чтобы избежать первоначального: «Я».

Обновление наших определений услуг для использования анонимных функций

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


function simplarity_init() {
  ...
  $plugin['settings_page'] = 'simplarity_service_settings';
  ...
}
...
function simplarity_service_settings( $plugin ){
  static $object;

  if (null !== $object) {
    return $object;
  }

  $object = new Simplarity_SettingsPage( $plugin['settings_page_properties'] );
  return $object;
}

мы можем просто заменить это с внейной анонимной функцией:


function simplarity_init() {
  $plugin = new Plugin();
  ...
  $plugin['settings_page'] = function ( $plugin ) {
    static $object;

    if (null !== $object) {
      return $object;
    }
    return new SettingsPage( $plugin['settings_page_properties'] );
  };
  ...
}

Использование прыщей как плагинконтейнер

Прыщ представляет собой небольшой инъекции зависимости (DI) контейнер для PHP 5.3 «. Pimple имеет тот же синтаксис, что и наш простой плагинный контейнер. На самом деле наш плагин контейнер был вдохновлен Pimple. В этой части, мы будем расширять Прыщ и использовать его.

Скачать контейнер Pimple от GitHub и сохранить его в src / Simplarity /Pimple.php.

Откройте Pimple.php и замените пространство имен и название класса на:


...
namespace Simplarity;

/**
 * Container main class.
 *
 * @author  Fabien Potencier
 */
class Pimple implements ArrayAccess
...

Откройте Plugin.php и замените весь код:

<?php
namespace Simplarity;

class Plugin extends Pimple {

  public function run(){ 
    foreach( $this->values as $key => $content ){ // Loop on contents
      $content = $this[$key];

      if( is_object( $content ) ){
        $reflection = new ReflectionClass( $content );
        if( $reflection->hasMethod( 'run' ) ){
            $content->run(); // Call run method on object
        }
      }
    }
  }
}

Теперь давайте изменим определение службы в simplarity.php на:

$plugin['settings_page'] = function ( $plugin ) {
  return new SettingsPage( $plugin['settings_page_properties'] );
};

По умолчанию каждый раз, когда вы получаете услугу, Pimple возвращает тот же экземпляр. Если вы хотите, чтобы для всех вызовов был возвращен другой экземпляр, оберните анонимную функцию factory() методом:

$plugin['image_resizer'] = $plugin->factory(function ( $plugin ) {
  return new ImageResizer( $plugin['image_dir'] );
});

Заключение

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

Образцы кода

Ресурсы

Источник: smashingmagazine.com

Великолепный Журнал

Великолепный, сокрушительный, разящий (см. перевод smashing) независимый журнал о веб-разработке. Основан в 2006 году в Германии. Имеет няшный дизайн и кучу крутых авторов, которых читают 2 млн человек в месяц.

Добавить комментарий

%d такие блоггеры, как: