Intereting Posts
Как продолжить процесс после ответа на запрос ajax в PHP? Преобразование слов в числа в PHP Доступ к значениям массива с использованием ключа массива от Twig Как я могу отправить данные с PHP на IP-адрес через UDP? Как поймать эту ошибку: «Примечание: Неопределенное смещение: 0» CakePHP 2 – Проверка полей пароля php-число с плавающей запятой, показанное в экспоненциальной форме В чем разница между echo и printf Подключение базы данных MySQL MySQL Передача пользовательских входных данных с html на php-страницу и отображение содержимого на html-странице без перезагрузки Как загрузить файл PDF, созданный с помощью TCPDF (PHP) с помощью AJAX (jQuery)? Должны ли мои функции PHP принимать массив аргументов или я должен явно запрашивать аргументы? Создание ISODate для MongoDB с помощью PHP Как пропустить ассоциативный массив и получить ключ? Инфраструктура PHP и индекс массива

PHP-мышление ООП: отправка и получение сообщения: я правильно понял?

См. «Обновления» в конце:

Текущая база кода имеет 1.4k-строку чисто процедурного кода, который отправляет sms (имеет бизнес-логику, db-связь и все в одном гигантском, if условно вложенное бесчисленное множество, if s, никаких функций, полных литералов, подлинного кандидата DailyWTF? ). И я решил укусить пулю и переписать всю чертову с нуля.
Дело в том, что это будет мой первый опыт ООП. Я читал как можно больше об OOD и о хорошей практике и решил начать с чего-то простого. Я хочу реализовать отправку / получение сообщений (в основном текст / SMS, но MMS, электронная почта должны быть включены в будущем). Поэтому я написал следующее в качестве своего первого сообщения

 interface MessageInterface { public function setType($type); public function getType(); public function setContent($content); public function getContent(); public function sendMessage(); //add more functionalities later } class Message implements MessageInterface { private $_type; private $_content; public function setType($type) { $this->_type = $type; } public function getType() { return $this->_type; } public function setContent($content) { if ($this->_type = 'text') { $this->_content = $content; return TRUE; // report success } else { return FALSE; } // report failure } public function getContent() { return $this->_content; } public function sendMessage() { if ($this->_type == 'text') { print "Sending ".$this->getContent()." as ".$this->getType()." message\n"; //do the actual implementation later return TRUE; // report success } else { return FALSE; } // report failure } } $msg = new Message(); $msg->setType('text'); print $msg->getType() . "\n"; //text $result = $msg->setContent('Hello World!'); if($result) $result2 = $msg->sendMessage(); //Sending Hello World! as text message if($result2) print 'Hurray ! Mission accomplished !!'; 

Я не думаю, что правильно применяю концепцию полиморфизма. Я чувствую, что if бы не было, верно? Возможно, они необходимы для setContent() но как насчет sendMessage() ? Поэтому я подумал, что отделив отправляющую часть в свой class SendMessage implements SendMessageInterface . который будет иметь свои собственные переменные для $server, $protocol и методов для отправки электронной почты и текста и т. д. Но при написании этого класса я понял, что if s снова ползут, как if($msg->getType() == 'text') условные обозначения. Чтобы добавить к этому, я создаю новый класс, который отделяет часть действия моего объекта, который меня путает (например, class door должна отвечать за реализацию методов close() и open() ).

Теперь либо я принимаю, что if всегда будет там (что, похоже, побеждает всю цель полиморфизма), или я должен делать что-то неправильно .
С точки зрения пользователя, я представляю себе что-то вроде:

 $msg = new Message(); $msg->setType('email'); //or 'text' or 'mms' etc. $msg->setContent($content); //eg $content=array('subject'=>'foo','body'=>'bar') $msg->sendMessage(); //if the last line is not possible, then perhaps //$sender = new SendMessage($msg); //$sender->send(); 

что мне здесь не хватает? невозможно достичь $msg->sendMessage(); ? Должны ли / нужны ли мне разные классы сообщений ( MessageEmail , MessageText и т. Д.)? Должен ли я отделить SendMessage (и, возможно, иметь $msg->sendMessage(); называть его?)

// и это когда я даже не думал о получении сообщения ! Боже, помоги мне !! 🙁


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

 a. Message Class(es) (type, content, sender, receiver, DateTime of send/receive etc.) Responsibilities: creating and modifying messages ascribing consistent and appropriate characteristics of a message b. Send Class(es) (protocol, header info, server/operator to use) Responsibilities: Sending messages Changing the state of Message (for setting send DateTime of Message) e. Database Class(es) (id, content, to, from, time etc.) Responsibilities: Represent Message for storage. CRUD (Create, Read, Update, Delete) actions on this representation for DBMS. e. Interfaces (MAX_MESSAGE_LENGTH, TIMEOUT etc. ) Responsibilities: Provide interface for communication between various modules. 

Я считаю, что моя основная причина путаницы заключалась в смешивании интерфейсов с полиморфизмом ( см. Комментарий ). Как вы оцениваете это?


Обновление 16 августа 2011 г.
В основном я использовал интерфейсы, чтобы навязывать функциональность. Вот краткая версия файла interface.php

 interface MessageInterface { //omitting getters for clarity public function setType($type); public function setSender(IdentityInterface $sender); public function setReceiver(IdentityInterface $receiver); public function setSendGateway(GatewayInterface $sendGateway); } interface IdentityInterface { public function setName($name); public function setAddress($address); } interface GatewayInterface { public function setProtocol($protocol); public function send(IdentityInterface $sender, IdentityInterface $receiver, ContentInterface $content); } 

(нет причудливых вещей, поскольку я еще не интегрировал class GatewaySMPP implements GatewayInterface в мой основной класс Message который выглядит так:

 class Message implements MessageInterface { private $_type; private $_content; private $_sender; private $_receiver; private $_sendGateway; //private $_receiveGateway; private $_dataStorage; public function __construct( $type = NULL, $content = NULL, IdentityInterface $sender = NULL, IdentityInterface $receiver = NULL, GatewayInterface $sendGateway = NULL ) { $this->setType($type); $this->setContent($content); ($sender === NULL) ? $this->setSender(new Identity()) : $this->setSender($sender); ($receiver === NULL) ? $this->setReceiver(new Identity()) : $this->setReceiver($receiver); //similarly for $setSendGateway etc. } //setters and getters, omitting for clarity public function send(...) { //testing pending $this->_sendGateway->send($this->getSender(), $this->getReceiver(), $this->getContent ...) } 

Интересной частью было внедрение GatewaySMPP, которое включало множество операций сокета и проверку ответов. Мне просто нужно написать public function send() обёртки public function send() вокруг private function _send{PDU,SM} .

Хотя я думал об интеграции GatewaySMPP, я понял, что буду открывать / закрывать сокеты для соединения SMPP для каждой операции отправки сообщений. Это нормально для упражнений / тестирования, но на практике мне кажется, что мне может понадобиться изменить мою логику, чтобы использовать существующее соединение. Вопрос в том, как? Вот текущая логика:

 class GatewaySMPP { private $_socket,$_port,$_host //etc. public function __construct($host,$port,$user,$passwd) { $this->_socket = FALSE; $this->_host = $host; //initialize other private variables } public function init() { if($this->_socket !== FALSE) return FALSE; //socket already in use $this->_socket = fsockopen($this->_host, $this->_port ...) //prepare bind statement for initiating SMPP connection and fwrite to socket $this->_sendPDU(BIND, $data) } public function send($receiver, $sender, $message, ...) { //use private functions which do actual socket operations $this->_sendSM($receiver, $sender, $message, ...) } public function end() { if($this->_socket === FALSE) return; //socket already closed this->_sendPDU(UNBIND, ''); //omitting response check $result = fclose($this->_socket); //omitting response check } 

Q. Проблема, с которой я столкнулся, состоит в том, что каждый объект GatewaySMPP будет иметь свой собственный $ _socket, поэтому я подумал о том, чтобы сделать singleton ( содрогание ) GatewaySMPP или использовать какую-либо переменную global / state для отслеживания сокетов для повторного использования. Лучшая идея, которая приходит мне на ум, заключается в том, что потребитель этих классов использует следующую логику. 1. Создайте и используйте одиночный $objGatewaySMPP для всех $objectMessage[] 2. objGatewaySMPP->init(); 3. foreach($objMessage[] as $msg) $msg->send(); 4. objGatewaySMPP->end(); , Это все еще оставляет проблему одновременных вызовов разных пользователей класса? Предложения / комментарии, пожалуйста.

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

 <?php // Message Types abstract class Message { private $content; // for email this is the body of the email / for sms it is the 140 characters private $sendService; public function __construct(SendService $sendService){ $this->sendService = $sendService; } public function send($recipient) { $this->sendService->send($recipient, $this); } } class EmailMessage extends Message { private $subject; private $header; //setters and getters / maybe a constructor } class SMSMessage extends Message { private $from; //setters and getters / maybe a constructor } //Services for sending messages interface SendService { function send(Recipient $recipient, $message); } class EmailSendService implements SendService { function send($recipient, EmailMessage $message){ // you can use only the attributes from the recipient that you need (email address) // you can be sure that the message has a header and a subject because you are enforcing // the type allowed to be passed to this function // do email sending stuff } } class SMSSendService implements SendService { function send($recipient, SMSMessage $message){ // you can use only the attributes from the recipient that you need (tel number) // do sms sending stuff } } // Defines a 'user' that can be used for both messge types class Recipient { private $email; private $tel; private $name; //setters and getters } // how you would use the above // 1 - set up recipient - in the real world you would probably have something that would provide this // to you, like a database lookup $recipient = new Recipient(); $recipient->setEmail('abc@def.com'); $recipient->setName('Herp Derp'); $recipient->setTel('07770000000000'); // 2 - get a service for sending your message $sendService = new SMSSendService(); // 3 - create your message by passing it a service which it can use to send itself $message = new SMSMessage($sendService); // 4 - set attributes of your message and then send (passing a recipient to send to) $message->setContent('lorem ipsum herp derp doop'); $message->send($recipient); 

С интерфейсами вы можете сделать это без расширения другого класса. И это здорово.

Я попробую сказать в коде (потому что мой английский хуже, чем мой PHP)

 <?php Interface IMessage { public function Send(); } class EMail implements IMessage { private $content; private $to; private $subject; public function __construct($to, $subject, $content) { $this->to = $to; $this->subject = $subject; $this->content = $content; } public function Send() { mail($this->to, $this->subject, $this->content); } } class SMS implements IMessage { private $num; private $from; private $message; public function __construct($num, $message, $from = '') { $this->num = $num; $message = substr(trim($message), 0, 140); $from = empty($from) ? $num : $from; } public function Send() { //... } } 

Учитывая, что метод setContent будет использоваться только для текстовых типов (ну, я полагаю, это потому, что вы выполняете условную проверку), кажется логичным разбить класс каким-то образом, возможно, на базовое слово Message и SMSMessage ala SMSMessage и MMSMessage . В SMSMessage вы можете определить SetContent() а затем, возможно, AttachImage() например, для MMSMessage . Другим подходом является определение SetContent() как абстрактного в сообщении базового класса, а затем принуждение наследователей определять этот метод – то есть, если вы планируете сделать некоторую логику в этом методе.

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

Перейдите на другой язык. (без шуток). Поддержка ООП в PHP совершенно отсутствует, и я бы не хотел пытаться программировать в ней для чего-то другого, кроме близких к сети задач.