DI-контейнер Foton — это система внедрения зависимостей с автоматическим разрешением аргументов конструктора через рефлексию. Контейнер сканирует модули в каталоге dev/modules, анализирует их конструкторы, строит дерево зависимостей и генерирует готовые фасадные классы с уже разрешёнными зависимостями.
Для понимания работы этой системы выполните следующие действия по шагам:
<?php
// dev/modules/TestDI.php
namespace Modules;
class TestDI
{
public $fileLoad;
public function __construct(FileLoad $object)
{
$this->fileLoad = $object;
}
public function test($text)
{
return 'Class Load:' . get_class($this->fileLoad) . ' Text: ' . $text;
}
}Если конструктор принимает объект с type-hint, контейнер автоматически найдёт этот класс и рекурсивно разрешит его собственные зависимости.
<?php
namespace Dev;
class Facade
{
private $core;
public function __construct()
{
$this->core = new \Foton\Core();
}
public function realise20($arg = [])
{
return [
'Test' => ['class' => 'Modules\TestDI', 'arg' => []],
];
}
public function realise12($arg = [])
{
return [
'Test' => ['class' => 'Modules\TestDI', 'arg' => []],
];
}
}Структура возвращаемого массива:
'ИмяФасада' => [ 'class' => 'Modules\ИмяКласса', // класс модуля 'arg' => ['paramName' => value], // переопределение аргументов конструктора ] Ключ 'Test' — имя, по которому модуль будет доступен через $this->core->obj('Test') 'class' — полное имя класса модуля 'arg' — ассоциативный массив переопределяемых аргументов конструктора (имя параметра → значение). Если аргумент не указан и не является объектом, генерируется предупреждение
# Базовая генерация фасадов php foton di autoload # Генерация + вывод всех найденных модулей с зависимостями php foton di autoload load # Генерация + вывод ошибок php foton di autoload error # Генерация + вывод всех созданных фасадов php foton di autoload facade
$result = $this->core->obj('Test')->realise20()->test('text'); // Вывод: Class Load:\Modules\FileLoad Text: text
Цепочка вызовов: obj('Test') возвращает сгенерированный фасад Dev\DI\Facades\Test, метод realise20() создаёт экземпляр \Modules\TestDI со всеми зависимостями и возвращает его, test('text') — метод самого модуля.
<?
class Test
{
public $propertyClass;
public function realise20($arg = [])
{
// Сначала создаются зависимости (в обратном порядке)
$this->propertyClass["Class_Foton_Core"] = new \Foton\Core();
$this->propertyClass["Class_Modules_FileLoad"] = new \Modules\FileLoad(
$this->propertyClass["Class_Foton_Core"]
);
// Аргументы можно переопределить через $arg
if (count($arg) > 0) {
$arg = array_replace([$this->propertyClass["Class_Modules_FileLoad"]], $arg);
} else {
$arg = [$this->propertyClass["Class_Modules_FileLoad"]];
}
// Создание целевого модуля
$this->propertyClass["Test"] = new \Modules\TestDI(...$arg);
return $this->propertyClass["Test"];
}
}Зависимости создаются снизу вверх: сначала классы без зависимостей, затем классы, которые их используют, и в конце — целевой модуль. Массив $arg позволяет переопределить аргументы конструктора при вызове.
Примеры использования
Пример 1. Модуль с несколькими зависимостями
<?
// dev/modules/Logger.php
namespace Modules;
class Logger
{
public $fileLoad;
public function __construct(FileLoad $fileLoad)
{
$this->fileLoad = $fileLoad;
}
public function write($message)
{
$this->fileLoad->save('log.txt', $message);
return "Logged: $message";
}
}<?
// dev/modules/UserService.php
namespace Modules;
class UserService
{
public $logger;
public $fileLoad;
public function __construct(Logger $logger, FileLoad $fileLoad)
{
$this->logger = $logger;
$this->fileLoad = $fileLoad;
}
public function register($name)
{
$this->logger->write("User registered: $name");
return "User $name registered";
}
}Конфигурация в Facade:
public function realise30($arg = []) { return [ 'User' => ['class' => 'Modules\UserService', 'arg' => []], ]; }
Контейнер рекурсивно разрешит цепочку: UserService → Logger → FileLoad → Foton\Core. Сгенерированный фасад:
public function realise30($arg = []) { $this->propertyClass["Class_Foton_Core"] = new \Foton\Core(); $this->propertyClass["Class_Modules_FileLoad"] = new \Modules\FileLoad( $this->propertyClass["Class_Foton_Core"] ); $this->propertyClass["Class_Modules_Logger"] = new \Modules\Logger( $this->propertyClass["Class_Modules_FileLoad"] ); if (count($arg) > 0) { $arg = array_replace([ $this->propertyClass["Class_Modules_Logger"], $this->propertyClass["Class_Modules_FileLoad"] ], $arg); } else { $arg = [ $this->propertyClass["Class_Modules_Logger"], $this->propertyClass["Class_Modules_FileLoad"] ]; } $this->propertyClass["User"] = new \Modules\UserService(...$arg); return $this->propertyClass["User"]; }
Вызов:
$result = $this->core->obj('User')->realise30()->register('Иван');
Пример 2. Переопределение аргументов конструктора
Модуль со скалярным аргументом:
<?
// dev/modules/Cache.php
namespace Modules;
class Cache
{
public $fileLoad;
public $ttl;
public function __construct(FileLoad $fileLoad, $ttl = 3600)
{
$this->fileLoad = $fileLoad;
$this->ttl = $ttl;
}
public function get($key)
{
return "Cache[$key] ttl={$this->ttl}";
}
}Конфигурация с переопределением ttl:
public function realise40($arg = []) { return [ 'Cache' => ['class' => 'Modules\Cache', 'arg' => ['ttl' => 60]], ]; } public function realise41($arg = []) { return [ 'Cache' => ['class' => 'Modules\Cache', 'arg' => ['ttl' => 86400]], ]; }
После генерации можно использовать разные конфигурации:
/ Короткий TTL $short = $this->core->obj('Cache')->realise40()->get('user:1'); // Вывод: Cache[user:1] ttl=60 // Длинный TTL $long = $this->core->obj('Cache')->realise41()->get('user:1'); // Вывод: Cache[user:1] ttl=86400
Краткая инструкция:
# 1. Положить модуль в dev/modules/ # 2. Описать релиз в Dev\Facade # 3. Сгенерировать php foton di autoload # 4. Использовать $this->core->obj('ИмяФасада')->имяРелиза()->методМодуля(аргументы);