- PVSM.RU - https://www.pvsm.ru -
В этой статье я хочу ещё раз поговорить о разработке архитектуры приложения с использованием инверсии зависимости (Inversion of Control [1]).
Я уже писал на хабре о библиотеке IoC [2] и о Modular [3]. Теперь я пошел ещё дальше и упростил все что только можно и попробую объяснить принципы построения архитектуры. А так же расскажу о новой библиотеке Granula [4].
Давайте представим, что мы хотим сделать библиотеку для управления пользователями на сайте. Первое что нам понадобится, это место где мы будем хранить информацию о
наших пользователях.
Опишем интерфейс хранилища:
interface StorageInterface
{
public function set($key, $value);
public function get($key);
public function save();
public function load();
}
Отлично, теперь нам нужна реализация этого интерфейса. Для начала будем хранить информацию в файлах. Создадим класс FileStorage.
class FileStorage implements StorageInterface
{
private $file = 'data.json';
private $data = array();
public function set($key, $value)
{
$this->data[$key] = $value;
}
public function get($key)
{
return $this->data[$key];
}
public function save()
{
file_put_contents($this->file, json_encode($this->data));
}
public function load()
{
$this->data = json_decode(file_get_contents($this->file));
}
}
Теперь создадим класс пользователя
class User
{
public function __construct(StorageInterface $storage)
{
}
}
Теперь что бы создать экземпляр класса User:
$user = new User(new FileStorage());
Отлично, а что если кто-то из пользователей нашей библиотеки захочет вместо файлов использовать базу данных? Для этого ему нужно создать класс DatabaseStorage, реализовать интерфейс StorageInterface и заменить все вхождения FileStorage. Но изменение библиотеки сулит проблемы с её обновлениями.
Что бы этого избежать, давайте, введём опции:
$options = array(
'StorageInterface' => 'FileStorage',
);
$user = new User($option['StorageInterface']);
Теперь что бы заменить FileStorage на DatabaseStorage, нужно всего лишь указать это в опциях:
$options['StorageInterface'] = 'DatabaseStorage';
То, что мы сейчас назвали опциями, на самом деле является контейнером IoC.
Именно такая архитектура позволяет строить наиболее гибкие приложения и библиотеки.
В своей предыдущей статье я рассказывал о библиотеке Modular, я продолжил развивать её, постарался упростить все для наилучшего понимания. Её основной задачей является обучение применения IoC на практике, создания модульной архитектуры приложения.
Теперь она называется Granula [4].
Любая библиотека может быть модулем для гранулы. Например из компонентов Symfony Components [5] можно создать MVC приложение на подобии самой Symfony.
Каждый модуль гранулы должен быть описан своим классом:
use GranulaModule;
use InversionContainer;
class MyModule extends Module
{
public function build(Container $container)
{
// Опишите свой модуль здесь.
}
}
Например, описание библиотеки, которую мы создавали в начале статьи будет таким:
$container['StorageInterface'] = 'FileStorage';
Можно даже сократить ещё больше:
$container[] = 'FileStorage';
Но в таком случае не будет работать ленивая загрузка классов, так как FileStorage будет загружен Inversion [6](библиотекой IoC контейнеров) сразу для определения его интерфейсов.
$container['request']
= $container['SymfonyComponentHttpFoundationRequest']
= new Factory('SymfonyComponentHttpFoundationRequest', 'createFromGlobals');
$container['SymfonyComponentConfigFileLocator']
= 'SymfonyComponentConfigFileLocator';
$container['DoctrineCommonAnnotationsReader']
= 'DoctrineCommonAnnotationsAnnotationReader';
$container['SymfonyComponentRoutingLoaderAnnotationClassLoader']
= 'GranulaRouterAnnotatedRouteControllerLoader';
$container['SymfonyComponentConfigLoaderLoaderInterface']
= 'SymfonyComponentRoutingLoaderAnnotationDirectoryLoader';
$container['request.context']
= $container['SymfonyComponentRoutingRequestContext']
= new Service('SymfonyComponentRoutingRequestContext');
$container['router']
= $container['SymfonyComponentRoutingRouterInterface']
= new Factory('GranulaRouterRouterFactory');
Затем все необходимые модули указываются в Front Controller:
class App extends GranulaApp
{
public function register()
{
return array(
new MyModule(),
// Список модулей
);
}
}
И в файле index.php запускаются:
$app = new App();
$app->run();
Я оформил все необходимые модули для создания полноценного MVC приложения. Что бы поиграться с ним используйте Composer [7] для установки:
composer create-project granula/app www
В него включены:
Contributors are Welcome!
Автор: Elfet
Источник [9]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/php-2/19922
Ссылки в тексте:
[1] Inversion of Control: http://ru.wikipedia.org/wiki/%D0%98%D0%BD%D0%B2%D0%B5%D1%80%D1%81%D0%B8%D1%8F_%D1%83%D0%BF%D1%80%D0%B0%D0%B2%D0%BB%D0%B5%D0%BD%D0%B8%D1%8F
[2] IoC: http://habrahabr.ru/post/132084/
[3] Modular: http://habrahabr.ru/post/149435/
[4] Granula: http://granula.github.com/
[5] Symfony Components: http://symfony.com/components
[6] Inversion: https://github.com/granula/inversion
[7] Composer: http://getcomposer.org/
[8] Управление зависимостями в PHP-коде: http://wiki.agiledev.ru/doku.php?id=ooad:manage_dependencies_in_php_code
[9] Источник: http://habrahabr.ru/post/158213/
Нажмите здесь для печати.