Какой наиболее эффективный подход для создания универсального метода выполнения 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, который очистит предыдущие значения, тут же можно установить вид запроса, и тут же можно описать, значения каких полей можно перенести с предыдущего запроса, что очень важно для использования. Либо на каждый тип запроса (метод на удаленном сервисе) пилить свой метод со своими порядками и аргументами, как говорил выше.