Какой наиболее эффективный подход для создания универсального метода выполнения 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
```
Как мне лучше организовать этот процесс, чтобы он был максимально эффективным и не требовал значительных изменений для каждого нового источника?
Чтобы оптимизировать метод `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Здесь выполняете логику в зависимости от typepublic function makeRequest(array $args, string $type) {if($type === "source1") {
Для каждого type нужно создать класс, который будет выполнять логику, описанную в его блоке if.
После, с помощью DI и полиморфизма, отрефакторить существующий код следующим образом:
Здесь Вы принимаете сервис вместо type
public function makeRequest(array $args, ApiServiceInterface $apiService) {
Здесь выполняете логику, но выполнение делегируете сервису$apiService->send();
Стоит получше подумать над именами классов, переменных и функций.
Вам зачем нужна прослойка? Что бы заменить некрасивый синтаксис curl_xxx на свой некрасивый?
Что бы код стал читаемым, нужно создавать класс, предоставляющий функционал удаленного сервиса, а не один гигантский request.
Обычно не доходят до того, чтобы создать под каждый тип запроса свой метод, но как минимум нужно создать метод request, который под капотом будет:
* обрабатывать авторизацию
* обрабатывать ошибки сети и отслеживать лимиты сервиса и отправлять повторные запросы
* выжидать необходимые таймауты
* обрабатывать пакетные запросы, к примеру если сервис требует постранично работать с данными
* регистрировать и обрабатывать обратные вызовы callback, если такие есть (само собой это уже другой метод)
Не рекомендуется все данные собирать в аргументах одного вызова, наоборот, пусть перед выходом нужно будет сделать инициализацию полей этого класса, в которых собирается все необходимое и вот тут пусть класс следит, что все необходимые данные заданы. т.е. должен быть метод типа startPrepare, который очистит предыдущие значения, тут же можно установить вид запроса, и тут же можно описать, значения каких полей можно перенести с предыдущего запроса, что очень важно для использования. Либо на каждый тип запроса (метод на удаленном сервисе) пилить свой метод со своими порядками и аргументами, как говорил выше.