Это мой первый class, не судите строго, а лучше подскажите где я ошибаюсь (а я ошибаюсь, чувство такое) и как правильно работать с классом Данный клас предназначен для полноценной работы Viber бота (перевожу из процедурного в ООП) PHP: //Подключаемся к БД $mysqli = new mysqli('ххх', 'ххх', 'ххх', 'ххх'); //Кодировка данных из базы $mysqli->query("SET NAMES 'utf8' "); // В случае ошибки подключения передаём false $mysqli = $mysqli->connect_errno ? false : $mysqli; Инициализируем класс. PHP: $handler = new Viber_Bot_Handler($mysqli, API_TOKEN)); Вот собственно сам класс: getContents() - принимает данные от Вайбера requestProcess() - покачто делает минимальную проверку на на тип присылаемого сообщения. Если тип text отвечает темже сообщением что нам пришло, в противном случае показываем ошибку sendResponse() - отправляет готовый ответ PHP: class Viber_Bot_Handler{ private $mysqli; private $api_token; private $api_url = "https://chatapi.viber.com/pa/send_message"; private $event; private $mess_type; private $mess_text; private $sender_id; private $sender_name; private $answers = [ "subscribed" => "Дякуємо, що підписались на нас!", "conversation_started" => "Розмова почалась!", "error_understand" => "Нажаль я вас не зрозуміла, напишіть будь ласка щось інше " ]; function __construct($mysqli, $api_token){ $this->mysqli = $mysqli; $this->api_token = (string) $api_token; $this->getContents(); } /* Получаем данные от Вайбера */ public function getContents(){ $request = file_get_contents('php://input'); $input = json_decode($request, true); if(!$input){return} $this->event = $input['event']; $this->mess_type = $input['message']['type']; // Тип присланного сообщения $this->mess_text = $input['message']['text']; // Текст сообщения $this->sender_id = $input['sender']['id']; // ID пользователя который нас пишет $this->sender_name = $input['sender']['name']; // Имя пользователя который нас пишет $this->requestProcess(); } public function requestProcess(){ $data['auth_token'] = $this->api_token; $data['receiver'] = $this->sender_id; $data['type'] = "text"; $data['min_api_version'] = 2; if($this->mess_type == 'text'){ $data['text'] = $this->mess_text; }else{ $data['text'] = $this->answers['error_understand']; } $this->sendResponse($data); } /* Отправляем готовый ответ пользователю */ public function sendResponse($param){ $resp_json = json_encode($param); $ch = curl_init($this->api_url); curl_setopt($ch, CURLOPT_POST, 1); curl_setopt($ch, CURLOPT_POSTFIELDS, $resp_json); curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: application/json')); $response = curl_exec($ch); $err = curl_error($ch); curl_close($ch); // Если ошибку существуют показываем $err // в противном случае $trsponse return ($err) ? $err : $response; } }
1. По стилю кода и именованию полей придерживайтесь PSR-1 и PSR-12. 2. В свежем PHP используйте типизацию. 3. Не вызывайте методы вроде $this->getContents() в конструкторе, а сделайте отдельный метод вроде $handler->handle() для запуска. 4. В $this->... присваивайте только настройки в конструкторе. Вместо присваивания промежуточных вещей $this->mess_text передавайте $input напрямую в методы вроде $this->requestProcess($input); 5. Внутренние меоды делайте приватными. 6. Не вызывайте лишний раз методы по цепочке друг из друга. Сделайте методы максимально независимыми от соседей и в методе handle() и управляйте процессом их вызова. 7. Для сообщений об ошибках используйте исключения. PHP: declare(strict_types=1); class ViberBotHandler { private static array $answers = [ 'subscribed' => 'Дякуємо, що підписались на нас!', 'conversation_started' => 'Розмова почалась!', 'error_understand' => 'Нажаль я вас не зрозуміла, напишіть будь ласка щось інше ' ]; private string $apiToken; private string $apiUrl; public function __construct( string $apiToken, string $apiUrl = 'https://chatapi.viber.com/pa/send_message' ) { $this->apiToken = $apiToken; $this->apiUrl = $apiUrl; } public function handle(): string { $input = $this->readInput(); $data = $this->generateResponse($input); return $this->sendResponse($data); } private function readInput(): array { $request = file_get_contents('php://input'); return json_decode($request, true, 512, JSON_THROW_ON_ERROR); } private function generateResponse(array $input): array { $data = []; $data['auth_token'] = $this->apiToken; $data['receiver'] = $input['sender']['id']; $data['type'] = 'text'; $data['min_api_version'] = 2; if ($input['message']['type'] === 'text') { $data['text'] = $input['message']['text']; } else { $data['text'] = self::$answers['error_understand']; } return $data; } private function sendResponse(array $data): string { $ch = curl_init($this->apiUrl); curl_setopt($ch, CURLOPT_POST, 1); curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data)); curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: application/json')); $response = curl_exec($ch); $error = curl_error($ch); curl_close($ch); if ($err) { throw new RuntimeException($error); } return $response; } } PHP: $handler = new ViberBotHandler($token); try { $response = $handler->handle(); echo 'Success: ' . $response; } catch (Exception $exception) { echo 'Error: ' . $exception->getMessage(); } А дальше уже можно декомпозировать вроде передачи $input снаружи и выноса отправки сообщений в ApiClient: PHP: class ViberBotHandler { private static array $answers = [ 'subscribed' => 'Дякуємо, що підписались на нас!', 'conversation_started' => 'Розмова почалась!', 'error_understand' => 'Нажаль я вас не зрозуміла, напишіть будь ласка щось інше ' ]; private ApiClient $client; private string $apiToken; public function __construct(ApiClient $client, string $apiToken) { $this->client = $client; $this->apiToken = $apiToken; } public function handle(array $input): string { $data = $this->generateResponse($input); return $this->client->sendMessage($data); } private function generateResponse(array $input): array { $data = []; $data['auth_token'] = $this->apiToken; $data['receiver'] = $input['sender']['id']; $data['type'] = 'text'; $data['min_api_version'] = 2; if ($input['message']['type'] === 'text') { $data['text'] = $input['message']['text']; } else { $data['text'] = self::$answers['error_understand']; } return $data; } } PHP: $client = new ApiClient($apiUrl); $handler = new ViberBotHandler($client, $token); try { $input = json_decode(file_get_contents('php://input'), true); $response = $handler->handle($input); echo 'Success: ' . $response; } catch (Exception $exception) { echo 'Error: ' . $exception->getMessage(); } К такому коду уже можно сочинять юнит-тесты.
@ElisDN спасибо за подробное описание и примеры, сегодня же начну изучать полученную информацию и применять
@mainprofilemail, тут ещё вот в чём загвоздка. Сам по себе класс это ещё не ООП. ООП это когда объекты взаимодействуют. Видите в последнем примере Дмитрий написал что объект ApiClient, передаётся в объект ViberBotHandler в качестве параметра.
Для понимания взаимодействия объектов советую видео по конструкторам и методам и похожий на ваш реальный пример написания геолокатора с продвинутой декомпозицией функциональности с таким же выносом HTTP-клиента. И аналогично по примеру написания реального приложения посмотрите процесс написания регистрации пользователей с юнит-тестами. Для дальнейшего развития себя как программиста советую изучать хорошие практики.
Спасибо, обязательно ознакомлюсь со всеми ссылками и рекомендациями. Вы очень хорошо объясняете и чётко доносите информацию (без воды). Спасибо за помощь и то что наставляете на верный путь. Кстати я начал тестировать и не знаю почему но приведение типов в некоторых местах невозможно. Я имею ввиду: PHP: private static array $answers = []; private string $apiToken; private string $apiUrl; Parse error: syntax error, unexpected 'array' (T_ARRAY), expecting function (T_FUNCTION) or const (T_CONST) in /storage/ssd3/422/12855422/public_html/index.php on line 6 С приведением в строки аналогичная ситуация. Ещё здесь: PHP: return json_decode($request, true, 512, JSON_THROW_ON_ERROR); Ошибка Warning: Use of undefined constant JSON_THROW_ON_ERROR - assumed 'JSON_THROW_ON_ERROR' (this will throw an Error in a future version of PHP) in /storage/ssd3/422/12855422/public_html/index.php on line 35 Fatal error: Uncaught TypeError: json_decode() expects parameter 4 to be integer, string given in /storage/ssd3/422/12855422/public_html/index.php:35 Stack trace: #0 /storage/ssd3/422/12855422/public_html/index.php(35): json_decode('', true, 512, 'JSON_THROW_ON_E...') #1 /storage/ssd3/422/12855422/public_html/index.php(25): ViberBotHandler->readInput() #2 /storage/ssd3/422/12855422/public_html/index.php(82): ViberBotHandler->handle() #3 {main} thrown in /storage/ssd3/422/12855422/public_html/index.php on line 35 Пришлось удалить два последних значения И ещё у нескольких методов убрал приведение типов потому что ожидался другой тип данных. Также и поступил со свойствами потому что это вызывало ошибку, но только почему не знаю. Можете подсказать? Версия php 7.2.18
Понял, спасибо большое. Кстати стал смотреть видео по вашей рекомендации, очень хорошие, мне нравится все четко и по делу