Как можно эффективно оптимизировать метод, который выполняет операции для всех других методов класса, чтобы избежать его излишней сложности?

Какой наиболее эффективный подход для создания универсального метода выполнения CURL-запросов, учитывающий различные методы, заголовки и настройки? У меня есть чат-бот для Telegram, написанный на PHP, с классом-парсером, где каждый метод отвечает за парсинг определенного источника. Результаты каждого метода передаются в индексный файл, который используется для отправки ответов в Telegram.

Чтобы избежать излишней нагрузки на методы для разных источников, я реализовал общий метод, который выполняет CURL-запросы к конкретным источникам с установленными для них соответствующими настройками. 

Функция выглядит следующим образом:

```php
public function makeRequest(array $args, string $type) {
}
```

Например, в одном случае требуется добавить `curl_setopt($curl, CURLOPT_PROXY, $proxyIp);`, а в другом - нет; также различаются ссылки и параметры запроса. Специфика каждого запроса передается через `$args`, а по переменной `$type` определяется источник. Это реализовано следующим образом:

```php
if($type === "source1") {
    
    $proxiesArr = array('72.37.217.3:4145', '174.77.111.196:4145');
    
    $randProx = array_rand($proxiesArr, 1);
    
    $proxyIp = $proxiesArr[$randProx];
    
    // $proxyIp = '174.77.111.196:4145';
    $url1 = $args[0] . $args[1];
    $headers = [
        'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.105 YaBrowser/21.3.3.230 Yowser/2.5 Safari/537.36'
    ];

    $curl = curl_init();

    curl_setopt($curl, CURLOPT_PROXY, $proxyIp);
    curl
```

Как мне лучше организовать этот процесс, чтобы он был максимально эффективным и не требовал значительных изменений для каждого нового источника?
  • 16 октября 2024 г. 8:23
Ответы на вопрос 4
Чтобы оптимизировать метод `makeRequest` для выполнения CURL-запросов к различным источникам, стоит учитывать следующие подходы:

### 1. Использование конфигураций для источников

Создайте массив конфигураций для каждого источника, который будет содержать ключевые параметры, такие как URL, заголовки, настройки прокси и другие. Это позволит вам легко обновлять и изменять конфигурации без необходимости изменить основной код.

```php
private $sourcesConfig = [
    'source1' => [
        'url' => 'https://example.com/api',
        'use_proxy' => true,
        'headers' => [
            'User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 ...'
        ],
        'proxies' => ['72.37.217.3:4145', '174.77.111.196:4145']
    ],
    'source2' => [
        'url' => 'https://anotherexample.com/api',
        'use_proxy' => false,
        'headers' => [
            'User-Agent: Mozilla/5.0 ...'
        ],
    ],
    // добавьте другие источники по необходимости
];
```

### 2. Параметризация запроса

Теперь вы можете изменить метод `makeRequest`, чтобы он считывал конфигурацию на основе переданного типа и использовал её для задания параметров CURL:

```php
public function makeRequest(array $args, string $type) {
    if (!isset($this->sourcesConfig[$type])) {
        throw new InvalidArgumentException("Неизвестный источник: {$type}");
    }

    $config = $this->sourcesConfig[$type];

    $curl = curl_init();

    // Установка URL
    $url = $config['url'] . '/' . implode('/', $args);
    curl_setopt($curl, CURLOPT_URL, $url);

    // Установка заголовков
    if (isset($config['headers'])) {
        curl_setopt($curl, CURLOPT_HTTPHEADER, $config['headers']);
    }

    // Установка прокси, если это необходимо
    if ($config['use_proxy'] && isset($config['proxies'])) {
        $proxyIp = $config['proxies'][array_rand($config['proxies'])];
        curl_setopt($curl, CURLOPT_PROXY, $proxyIp);
    }

    // Другие настройки
    curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
    
    // Выполнение запроса
    $response = curl_exec($curl);
    if (curl_errno($curl)) {
        throw new RuntimeException('Ошибка CURL: ' . curl_error($curl));
    }

    curl_close($curl);
    return $response;
}
```

### 3. Обработка ответов

Добавьте возможность обработки ответов в зависимости от типа источника, если вам нужно сделать это. Это может быть как отдельный метод, так и обрабатываемый внутри `makeRequest`. 

### 4. Создание интерфейсов

Если количество источников существенно увеличивается или методы становятся разнообразными, вы можете создать интерфейс, который будет реализован для каждого типа источника, чтобы структура оставалась единой, а логика источников была отделена.

### 5. Логирование и отладка

Не забудьте добавить логирование любых ошибок, чтобы можно было легко отслеживать проблемы при выполнении запросов. 

### Пример использования

Теперь, обращаясь к вашему методу, можно просто передать необходимый тип и аргументы:

```php
$response = $this->makeRequest(['param1', 'param2'], 'source1');
```

### Заключение

Таким образом, с помощью структурированной конфигурации каждый источник имеет собственный набор параметров, что позволяет легко добавлять и изменять источники в будущем, избегая дублирования кода. Также это обеспечивает чистоту и упрощает поддержку кода.
Сделать декомпозицию и разбить на несколько методов. Или даже на целый класс с группой различных методов с разными опциями.
Здесь Вы принимаете type 
public function makeRequest(array $args, string $type) {
Здесь выполняете логику в зависимости от type if($type === "source1") {

Для каждого type нужно создать класс, который будет выполнять логику, описанную в его блоке if.
После, с помощью DI и полиморфизма, отрефакторить существующий код следующим образом:

Здесь Вы принимаете сервис вместо type
public function makeRequest(array $args, ApiServiceInterface $apiService) {

Здесь выполняете логику, но выполнение делегируете сервису $apiService->send();

Стоит получше подумать над именами классов, переменных и функций.
Вам зачем нужна прослойка? Что бы заменить некрасивый синтаксис curl_xxx на свой некрасивый? 

Что бы код стал читаемым, нужно создавать класс, предоставляющий функционал удаленного сервиса, а не один гигантский request.

Обычно не доходят до того, чтобы создать под каждый тип запроса свой метод, но как минимум нужно создать метод request, который под капотом будет:
* обрабатывать авторизацию
* обрабатывать ошибки сети и отслеживать лимиты сервиса и отправлять повторные запросы
* выжидать необходимые таймауты
* обрабатывать пакетные запросы, к примеру если сервис требует постранично работать с данными
* регистрировать и обрабатывать обратные вызовы callback, если такие есть (само собой это уже другой метод)

Не рекомендуется все данные собирать в аргументах одного вызова, наоборот, пусть перед выходом нужно будет сделать инициализацию полей этого класса, в которых собирается все необходимое и вот тут пусть класс следит, что все необходимые данные заданы. т.е. должен быть метод типа startPrepare, который очистит предыдущие значения, тут же можно установить вид запроса, и тут же можно описать, значения каких полей можно перенести с предыдущего запроса, что очень важно для использования. Либо на каждый тип запроса (метод на удаленном сервисе) пилить свой метод со своими порядками и аргументами, как говорил выше.
Похожие вопросы