Класс обвязка для инструментария

 

Всем доброго времени суток. Это первая статья второй части цикла «Создать интернет-магазин с нуля». Как я писал в предыдущем посте, в этой части нам предстоит реализовать инструментарий движка RS-MINI. Инструментарий — это набор вспомогательных классов, которые призваны помогать разработчику при написание модуля для системы.

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

В теории все звучит замечательно, но встает вопрос: «Как же технически это реализовать?» По сути, эти самые инструментарии являются обычными классами. Располагаться они будут в двух местах:

  • в ядре, то бишь в папке /rs-mini/
  • в папке модулей

Хорошо, инструментарии это обычные классы. Тогда возникает вопрос: «Как мы будем использовать методы этих классов?». Так как мне не очень хочется для каждого контроллера, где будет использоваться тот или иной класс инструментария, подключать и поднимать отдельный объект класса (инструментария), мне пришла в голову идея написать класс обвязку, который будет поднимать объекты только по необходимости. Обращаться к методам инструментария мы будет вот так:

helper::getTranslit('привет мир!!!');

или вот так

helper::get('string')->getTranslit('привет мир!!!');

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

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

Так возникает следующий вопрос: «Как система узнала о существование класса string.class.php?» Для того что бы система знала о том или ином инструментарии, нам понадобится его зарегистрировать. Для этого в классе helper будет метод set(), в который нам понадобится передать два параметра:

  • псевдоним класса (для использовании его в методе get() того же класса)
  • неймспейс класса

Вот пример регистрации класса с псевдонимом string:

helper::set('string', '\helper\string');

Ладно, с этим понятно (надеюсь). Тогда: «Где производить эту самую регистрацию?» Все системные хелперы будут регистрировать в конфиге проекта (в классе /project/conf/config.class.php), а хелперы модулей — в конфиге модуля (их у нас пока нет, но это пока).

Из выше сказанного могу сделать вывод, что класс helper должен состоять из следующего списка методов:

  • __callStatic() — этот метод позволит добиться вызова метода без указания класса.
  • get() — метод позволит жестко указать из какого класса инструментария необходимо вызвать необходимый метод
  • create() — класс обвязка будет поднимать и хранить объекты инструментария в своем свойстве (по сути каждый из классов инструментария является синглтоном), но иногда нам, как разработчикам, необходимо будет использовать не уже поднятый объект, а новую копию. Этот метод позволит нам сделать это (создать и вернуть новый объект инструментария)
  • set() — метод позволит зарегистрировать класс в списке хелперов
  • getError() — этот метод необходим для того что бы прекратить работу движка в случае если разработчик пытается вызвать не существующий инструментарий

Код класса обвязкИ

Теперь когда я немного поговорил о идеи хелперов в системе RS-MINI, пришло время продемонстрировать класс обвязку.

Файл называется helper.class.php и лежит в папке /rs-mini/core/

<?php 
 
/*
 * @package RS-MINI
 * @copyright (c) 2015-2016 Alexey Glumov aka Rio-Shaman (support@rio-shaman.ru)
 * @license GNU General Public License version 2; see LICENSE.txt
 *
 */
 
namespace core;
 
if(!defined('RS-MINI')) die();
 
/*
 * helper v 1.0
 *  
 * класс обвязка для вспомогательных классов инструментария
 * написан для того что бы хранить методы в разных классах
 * а вызывать из одного
 *  
 * два варианта вызова
 *  - helper::методИнструментария(); - только в том  
 *                                     случае если метод
 *                                     имеет уникальное
 *                                     имя
 *  - helper::get('псевдоним инструментария')
 *            ->методИнструментария()
 *    ;
 *
 */
 
class helper
{
    /*
     * объекты инструментария (синглтоны)
     *
     * @var    - array
     * @access - private
     */
     
    private static $objectList = NULL;
     
    /*
     * список инструментария (псевдонимы (ключи)
     * и имена классов)
     *
     * @var    - array
     * @access - private
     */
     
    private static $aliasList = NULL;
     
    /*
     * по имени метода определяем объект класса в
     * котором есть вызываемый метод после чего
     * вызываем вызываемый метод из найденного объекта
     *  
     * внимание. пользоваться только в том случае если
     * метод имеет уникальное имя. в противном случае будет
     * вызван метод из первого найденного объекта. в случае если
     * уникальность не соблюдалась, можно воспользоваться методом
     * get и принудительно указать псевдоним (задавался при
     * регистрации инструментария) класса инструментария из которого
     * нужно вызвать метод
     *  
     * @access - public
     * @return - результат отработки вызываемого метода или die
     *
     * @param string name         - имя вызываемого метода
     * @param array  argumentList - список аргументов
     */
     
    public static function __callStatic($name, $argumentList)
    {
        // если нет списка объектов
        if (is_null(self::$aliasList))
            // выводим еррор
            self::getError('method ' . $name . ' is not found');
             
        // листаем инструменты
        foreach (self::$aliasList as $alias => $class)
            // если вызываемый метод существует в данном объекте
            if (method_exists($class, $name)) {
                // проверяем существует ли объект в списке уже
                // поднятых объектах
                if (!isset(self::$objectList[$alias]))
                    // если нет, поднимаем объект
                    self::$objectList[$alias] = new self::$aliasList[$alias]();
                 
                // запускаем метод
                return call_user_func_array(
                    array(
                        // объект
                        self::$objectList[$alias],
                        // метод объекта
                        $name
                    ),
                    // список передаваемых параметров
                    $argumentList
                );
            }
         
        // убиваем скрипт
        self::getError('method ' . $name . ' is not found');
    }
     
    /*
     * метод выбирает объект по алиасу (если такого
     * объекта нет, поднимает его)
     *  
     * @access - public
     *  
     * @param string alias - псевдоним хелпера
     */
     
    public static function get($alias)
    {
        // если объект существует в списке уже
        // поднятых объектах
        if (isset(self::$objectList[$alias]))
            // вертаем сслыку на этот объект
            return self::$objectList[$alias];
             
        // если существует только имя класса
        if (isset(self::$aliasList[$alias]))
            // поднимаем объект сохраняя его в списке
            return self::$objectList[$alias] = new self::$aliasList[$alias]();
         
        // если система ничего не знает про существование
        // запрашиваемого класса, то вертаем эррор
        self::getError('class ' . $alias . ' is not found');
    }
     
    /*
     * метод поднимает отдельный (независимый)
     * объект класса
     *  
     * @access - public
     *  
     * @param string alias - псевдоним хелпера
     */
     
    public static function create($alias)
    {
        // если система знает про сущ. запрашиваемого класса
        if (isset(self::$aliasList[$alias]))
            // поднимаем объект этого класса
            return new self::$aliasList[$alias]();
         
        // если система ничего не знает про существование
        // запрашиваемого класса, то вертаем эррор         
        self::getError('class ' . $alias . ' is not found');
    }
     
    /*
     * метод наполняет список именами классов инструментария
     *  
     * @access - public
     *  
     * @param string alias - псевдоним по которому будет доступен класс
     * @param string class - имя класса
     */
     
    public static function set($alias, $class)
    {
        self::$aliasList[$alias] = $class;
    }
     
    /*
     * метод вертает ошибку
     *  
     * @access - public
     *  
     * @param string message - сообщение ошибки
     */
     
    private static function getError($message)
    {
        // закрываем sql подключение
        sql::close();
         
        die('RS-MINI ERROR: ' . $message);
    }
}

Заключение

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

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

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

Всего Вам наилучшего, у меня на сегодня все!

Прикрепленные файлы

 

Возможно Вам будут интересны следующие заметки

Комментарии (4)

Ваше имя *
Сайт
Ваш E-mail *
Ваше сообщение *
 
Вы не подтвердили условия политики конфиденциальности.
SibWeb, 21 Августа 2016 г. 13:55 пишет:
Читатель
Здравствуйте, Алексей!
Интересная реализация хелперов.
А в будущем, что хотите написать...
И хотелось бы статьи про работу RS-Mini на PHP 7.
Алексей, 22 Августа 2016 г. 10:11 пишет:
Автор
Доброго времени суток.
А в будущем, что хотите написать...
даст бог все таки продолжу описывать создание своего мини движка
И хотелось бы статьи про работу RS-Mini на PHP 7.
RS-SITE хорошо работает под php 7.0 (ну за исключением того что пришлось переименовать класс string на класс str), а как я уже говорил, RS-MINI является попыткой переписать RS-SITE
Ответ для пользователя: SibWeb
Глад Валакас, 10 Декабря 2017 г. 15:54 пишет:
Читатель
А где продолжения? :(
Алексей, 11 Декабря 2017 г. 10:50 пишет:
Автор
Доброго времени суток. К сожалению продолжения пока нету :( Буду надеяться, что когда-нибудь у меня все же хватит времени продолжить цикл.
Ответ для пользователя: Глад Валакас