Задать вопрос
@Valentine5

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

Какой способ создания универсального метода для curl запросов, который используют разные методы с разным набором заголовков и настройками, является самым оптимальным? Кейс такой: написал чат-бот для Telegram на PHP. Есть класс-парсер, каждый метод которого парсит определенный источник информации. Потом результаты каждого метода отдаются в индексный файл, чтобы послать его ответом в телеграм.

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

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


Например, где-то нужно добавить curl_setopt($curl, CURLOPT_PROXY, $proxyIp);, где-то нет, где-то парсится одна ссылка, где-то другая, чуть с другими аргументами после ?

Специфика для каждого запроса подставляется из $args, а по $type определяется, к какому источнику делается запрос. Это происходит например, так:

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_setopt($curl, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS4);
        curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true);
        curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false); 
        curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($curl, CURLOPT_VERBOSE, 1); 
        curl_setopt($curl, CURLOPT_POST, false);
        curl_setopt($curl, CURLOPT_URL, $url1);

        $result = curl_exec($curl);

        if(curl_exec($curl) === false)
        {
        echo 'Ошибка curl: ' . curl_error($curl);
        } else {
        echo 'Операция завершена без каких-либо ошибок';
        }

        return $result;
        }


Однако такая схема делает общий метод для curl очень громоздким: более 200 строк.. И это довольно трудно читать...

Подскажите, есть ли способ более красиво и четко такое написать? Не if($type === "source1") { и бесконечные If-ы, а что-то еще?

Может быть в коммерческой эффективной разработке это делается абстрактным классом или интерфейсом? Может, список заголовков для curl надо формировать в методах для отдельных источников? Подскажите, пожалуйста, как сделать профессиональнее?
  • Вопрос задан
  • 144 просмотра
Подписаться 1 Средний 2 комментария
Пригласить эксперта
Ответы на вопрос 4
vhood
@vhood
Не забывайте отмечать решения
Здесь Вы принимаете type
public function makeRequest(array $args, string $type) {
Здесь выполняете логику в зависимости от typeif($type === "source1") {

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

class SpecificTypeApiService implemets ApiServiceInterface
{
    public function send()
   {
//код ниже просто скопирован, стоит вынести что-то в параметры, что-то в конструктор и сделать код более элегантным
//можно сделать абстрактный класс и делегировать ему общий для разных type (сервисов) функционал
    $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_setopt($curl, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS4);
        curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true);
        curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false); 
        curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($curl, CURLOPT_VERBOSE, 1); 
        curl_setopt($curl, CURLOPT_POST, false);
        curl_setopt($curl, CURLOPT_URL, $url1);

        $result = curl_exec($curl);

        if(curl_exec($curl) === false)
        {
        echo 'Ошибка curl: ' . curl_error($curl);
        } else {
        echo 'Операция завершена без каких-либо ошибок';
        }

        return $result;
   }
}


После, с помощью DI и полиморфизма, отрефакторить существующий код следующим образом:

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

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

Стоит получше подумать над именами классов, переменных и функций.
Ответ написан
Комментировать
VoidVolker
@VoidVolker
Dark side eye. А у нас печеньки! А у вас?
Сделать декомпозицию и разбить на несколько методов. Или даже на целый класс с группой различных методов с разными опциями.
Ответ написан
Комментировать
@rPman
Вам зачем нужна прослойка? Что бы заменить некрасивый синтаксис curl_xxx на свой некрасивый?

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

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

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

Войдите, чтобы написать ответ

Похожие вопросы