Skip to content

Оптимизация инстанциирования (DEEPSEEK) #16

@KarelWintersky

Description

@KarelWintersky

Вот оптимизированная версия вашего кода. Основная идея - разделить компиляцию (определение что вызывать) и инстанциирование (создание объектов):

private static function compileHandler($handler, bool $is_middleware = false): array|string|\Closure
{
    if (empty($handler)) {
        return [];
    }

    // closure
    if ($handler instanceof \Closure) {
        return $handler;
    }

    // [ \Path\To\Class:class, "method" ]
    if (is_array($handler)) {
        if (count($handler) == 2) {
            list($class, $method) = $handler;
        } else {
            $class = $handler[0];
            $method = '__invoke';
        }

        self::checkClassExists($class);
        self::checkMethodExists($class, $method);

        // Возвращаем информацию о классе и методе для дальнейшего инстанциирования
        return [
            'type' => 'class_method',
            'class' => $class,
            'method' => $method,
            'static' => false // будет определено при инстанциировании
        ];
    }

    // isString
    if (is_string($handler) && str_contains($handler, '@')) {
        // 'Class@method'
        list($class, $method) = Helper::explode($handler, [null, '__invoke'], '@');
        self::checkClassExists($class);
        self::checkMethodExists($class, $method);

        // Определяем статичность метода без создания экземпляра класса
        try {
            $reflection = new \ReflectionClass($class);
            $reflected_method = $reflection->getMethod($method);
            $isStatic = $reflected_method->isStatic();
            
            return [
                'type' => 'class_method',
                'class' => $class,
                'method' => $method,
                'static' => $isStatic
            ];
            
        } catch (\ReflectionException $e) {
            self::$logger->error("Method '{$method}' not defined at '{$class}'", [self::$uri, self::$httpMethod, $class]);
            throw new AppRouterHandlerError("Method '{$method}' not defined at '{$class}'", 500, [
                'request' => self::$httpMethod . ' ' . self::$uri,
                'uri' => self::$uri,
                'method' => self::$httpMethod,
                'info' => self::$routeInfo,
                'rule' => self::$routeRule
            ]);
        }
    }

    // остался вариант "функция"
    self::checkFunctionExists($handler);
    return $handler;
}

// Новый метод для инстанциирования и вызова handler'а
private static function invokeHandler($compiledHandler, array $parameters = [])
{
    if (empty($compiledHandler)) {
        if (!self::$option_allow_empty_handlers) {
            throw new AppRouterHandlerError("Handler not found or empty", 500, [
                'request' => self::$httpMethod . ' ' . self::$uri,
                'uri' => self::$uri,
                'method' => self::$httpMethod,
                'info' => self::$routeInfo,
                'rule' => self::$routeRule,
            ]);
        }
        return;
    }

    $actor = null;
    
    // Если handler уже готов к вызову (замыкание или функция)
    if ($compiledHandler instanceof \Closure || is_string($compiledHandler)) {
        $actor = $compiledHandler;
    }
    // Если это информация о методе класса
    elseif (is_array($compiledHandler) && isset($compiledHandler['type'])) {
        if ($compiledHandler['type'] === 'class_method') {
            $class = $compiledHandler['class'];
            $method = $compiledHandler['method'];
            
            if ($compiledHandler['static']) {
                // Статический метод
                $actor = [$class, $method];
            } else {
                // Нестатический метод - создаем экземпляр
                if (array_key_exists($class, self::$instances)) {
                    $instance = self::$instances[$class];
                } else {
                    // @todo: тут надо бы передавать параметры в конструктор
                    $instance = new $class();
                    // Кешируем инстанс, если нужно
                    if (self::$option_cache_instances) {
                        self::$instances[$class] = $instance;
                    }
                }
                $actor = [$instance, $method];
            }
        }
    }

    if ($actor) {
        call_user_func_array($actor, $parameters);
    }
}

Использование:

// Компилируем handler (без инстанциирования)
$compiledHandler = self::compileHandler($handler, false);

// Инстанциируем и вызываем в нужном месте
self::invokeHandler($compiledHandler, $method_parameters);

Ключевые улучшения:

  1. Разделение ответственности:

    • compileHandler() только анализирует handler и возвращает структурированные данные
    • invokeHandler() занимается созданием объектов и вызовом
  2. Отложенное инстанциирование:

    • Объекты создаются только при необходимости вызова
    • Статические методы определяются без создания экземпляров
  3. Гибкость:

    • Можно кешировать скомпилированные handler'ы
    • Легче добавлять новые типы handler'ов
    • Более понятный поток выполнения
  4. Производительность:

    • Для статических методов не создаются экземпляры классов
    • Можно добавить кеширование инстансов через self::$option_cache_instances
  5. Чистота кода:

    • Каждый метод делает одну четкую задачу
    • Легче тестировать отдельные компоненты

Metadata

Metadata

Labels

questionFurther information is requested

Type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions