Всем доброго времени суток. Это первая статья второй части цикла «Создать интернет-магазин с нуля». Как я писал в предыдущем посте, в этой части нам предстоит реализовать инструментарий движка RS-MINI. Инструментарий — это набор вспомогательных классов, которые призваны помогать разработчику при написание модуля для системы.
Согласитесь, будет очень неудобно описывать алгоритм проверки электронной почты каждый раз когда нам (как разработчикам) понадобится создать поле в какой-нибудь форме какого-нибудь модуля. Хочется просто взять и вызвать валидатор мыла из недр ядра системы, и не задумываться о том как именно произойдет проверка.
В теории все звучит замечательно, но встает вопрос: «Как же технически это реализовать?» По сути, эти самые инструментарии являются обычными классами. Располагаться они будут в двух местах:
Хорошо, инструментарии это обычные классы. Тогда возникает вопрос: «Как мы будем использовать методы этих классов?». Так как мне не очень хочется для каждого контроллера, где будет использоваться тот или иной класс инструментария, подключать и поднимать отдельный объект класса (инструментария), мне пришла в голову идея написать класс обвязку, который будет поднимать объекты только по необходимости. Обращаться к методам инструментария мы будет вот так:
helper::getTranslit('привет мир!!!');
или вот так
helper::get('string')->getTranslit('привет мир!!!');
Почему существует два способа вызова одного и того же метода? Все очень просто, для сокращении вызова в контроллере я решил реализовать возможность использовать сразу имя метода, не указывая класс из которого этот метод будет вызываться. Работать это будет только в том случае если имя метода уникально. В противном случае будет вызван метод из первого найденного класса (при условии что этот метод существует в классе инструментария).
Если же нам будет известно, что создаваемый нами метод уже существует в системе, мы можем жестко указать из какого именно класса вызывать необходимый нам метод. В примере система поймет, что вызов необходимо производить из класса string.class.php.
Так возникает следующий вопрос: «Как система узнала о существование класса string.class.php?» Для того что бы система знала о том или ином инструментарии, нам понадобится его зарегистрировать. Для этого в классе helper будет метод set(), в который нам понадобится передать два параметра:
Вот пример регистрации класса с псевдонимом string:
helper::set('string', '\helper\string');
Ладно, с этим понятно (надеюсь). Тогда: «Где производить эту самую регистрацию?» Все системные хелперы будут регистрировать в конфиге проекта (в классе /project/conf/config.class.php), а хелперы модулей — в конфиге модуля (их у нас пока нет, но это пока).
Из выше сказанного могу сделать вывод, что класс helper должен состоять из следующего списка методов:
Теперь когда я немного поговорил о идеи хелперов в системе 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);
}
}
Класс очень хорошо расписан, думаю проблем с пониманием возникнуть не должно, тем не менее, если есть вопрос, задавайте, попытаюсь на них ответить.
В следующей статье, мы начнем делать сами классы инструментария, после чего и произведем тесты по работе класса обвязки.
Результат работы, Вы как всегда можете скачать в конце статьи.
Всего Вам наилучшего, у меня на сегодня все!
Интересная реализация хелперов.
А в будущем, что хотите написать...
И хотелось бы статьи про работу RS-Mini на PHP 7.