Framework Foton
Инструмент для профессиональной разработки web приложений
Работа с DI контейнером на Framework Foton

DI-контейнер Foton — это система внедрения зависимостей с автоматическим разрешением аргументов конструктора через рефлексию. Контейнер сканирует модули в каталоге dev/modules, анализирует их конструкторы, строит дерево зависимостей и генерирует готовые фасадные классы с уже разрешёнными зависимостями.

Для понимания работы этой системы выполните следующие действия по шагам:

  1. Создание модуля
    Модули размещаются в dev/modules/. Каждый модуль — класс в неймспейсе 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, контейнер автоматически найдёт этот класс и рекурсивно разрешит его собственные зависимости.

  2.  Конфигурация релизов
    Файл dev/facade.php содержит класс Dev\Facade. Каждый метод — это «релиз»: именованная конфигурация сборки модуля.
    <?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' — ассоциативный массив переопределяемых аргументов конструктора (имя параметра → значение). Если аргумент не указан и не является объектом, генерируется предупреждение
  3.  Запуск генерации Из командной строки введите 
    # Базовая генерация фасадов
    php foton di autoload
    
    # Генерация + вывод всех найденных модулей с зависимостями
    php foton di autoload load
    
    # Генерация + вывод ошибок
    php foton di autoload error
    
    # Генерация + вывод всех созданных фасадов
    php foton di autoload facade
  4. Использование
    После генерации модуль доступен через ядро:
    $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') — метод самого модуля.

  5. Посмотрите что у вас получилось, готовый файл класса со всеми зависимостями попадет в dev/di/facades/test.php 
    <?
    
    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('ИмяФасада')->имяРелиза()->методМодуля(аргументы);
© Copyright 2017 - 2026 Разработано на Framework Foton
Продукт зарегистрирован в Роспатенте