Intereting Posts
WordPress (расширение Woocommerce) – программно создавать новый порядок Лучший способ разрешить плагины для PHP-приложения Есть ли какой-либо возможный способ, которым посетитель может получить доступ к тому, что отправлено POST? пользователей для просмотра в локальном часовом поясе Как удалить пустые значения из многомерного массива в PHP? Перезагрузите часть страницы php без обновления всей страницы Как мы можем разделить предложение Скребок текстового файла без HTML? Как я могу скомпилировать linux для совместного использования со всеми дистрибутивами? почему 3 обратная косая черта равна 4 обратным слэшам в php? перебирать свойства класса php Невозможно переопределить функцию php Запросить последние данные от lastfm с помощью codeigniter и xmlrpc Два разных языка PHP и Java в одном приложении с PHP на Apache и Java на Tomcat Массив к объекту и объекту в массив в PHP – интересное поведение

Ввод интерфейса и общие классы

Я пытаюсь разобраться в принципах ООП и кодировать свои собственные классы. В качестве средства обучения я решил преобразовать несколько функций, которые я написал в WordPress для классов ООП. Эти функции работают вместе, чтобы выводить правильные почтовые ссылки на отдельных страницах в соответствии с реферерами (4 из них), заданными в URL-адресе.

Это настройка с базовым рабочим процессом ( рабочий процесс может меняться по мере продвижения ):

введите описание изображения здесь

4 переменных запроса устанавливаются в URL в соответствии с архивной страницей, т. Е. Одна переменная запроса для таксономических страниц, одна переменная запроса, заданная для страниц автора и т. Д. На странице никогда не может быть более одной настраиваемой переменной запроса. Эти 4 переменные извлекаются моим первым классом и проверяются против данной глобальной переменной, в данном случае $_GET . Я не жестко закодировал 4 переменные в моем классе, и это касается $_GET а также для проверки класса. Если значение существует в URL-адресе, пара ключ / значение возвращается через методы has* . Эти методы возвращают значение null если совпадение не найдено. (это необработанные данные, которые будут дезинфицированы / экранированы классами, которые будут использовать эти данные)

Вот полный класс

 <?php namespace PG\Single\Post\Navigation; /** * Test set values against the super global given. Returns conditional properties * which is boolean values. true is returned on success and false on failure. * * @param $superGlobalVar Super global to test the values against * @param (string) $authorReferrer * @param (string) $dateReferrer * @param (string) $searchReferrer * @param (string) $taxReferrer */ class RequestReferrerHandler implements RequestReferrerHandlerInterface { /** * @since 1.0.0 * @access protected * @var (array) $superGlobalVar */ protected $superGlobalVar; /** * @since 1.0.0 * @access protected * @var (string) $authorReferrer */ protected $authorReferrer; /** * @since 1.0.0 * @access protected * @var (string) $dateReferrer */ protected $dateReferrer; /** * @since 1.0.0 * @access protected * @var (string) $searchReferrer */ protected $searchReferrer; /** * @since 1.0.0 * @access protected * @var (string) $taxReferrer */ protected $taxReferrer; /** * Public constructor method. * * @param $superGlobalVar Super global to get data from * @param $authorReferrer Query variable from author referrer to test * @param $dateReferrer Query variable from date referrer to test * @param $searchReferrer Query variable from search referrer to test * @param $taxReferrer Query variable from taxonomy referrer to test */ public function __construct($superGlobalVar = null, $authorReferrer= null, $dateReferrer = null, $searchReferrer = null, $taxReferrer = null) { $this->superGlobalVar = $superGlobalVar; $this->authorReferrer = $authorReferrer; $this->dateReferrer = $dateReferrer; $this->searchReferrer = $searchReferrer; $this->taxReferrer = $taxReferrer; } /** * Setter setSuperGlobalVar. * * @since 1.0.0 * @param $superGlobalVar * @return $this */ public function setSuperGlobalVar($superGlobalVar) { $this->superGlobalVar = $superGlobalVar; return $this; } /** * Returns an array of super global variables. * * @since 1.0.0 * @return (array) $this->superGlobalVar */ public function getSuperGlobalVar() { return $this->superGlobalVar; } /** * Setter setAuthorReferrer * * @since 1.0.0 * @param $authorReferrer * @return $this */ public function setAuthorReferrer($authorReferrer) { $this->authorReferrer = $authorReferrer; return $this; } /** * Returns the value of the $authorReferrer property. * * @since 1.0.0 * @return (array) $this->authorReferrer */ public function getAuthorReferrer() { return $this->authorReferrer; } /** * Setter setDateReferrer. * * @since 1.0.0 * @param $dateReferrer * @return $this */ public function setDateReferrer($dateReferrer) { $this->dateReferrer = $dateReferrer; return $this; } /** * Returns the value of the $dateReferrer property. * * @since 1.0.0 * @return (array) $this->dateReferrer */ public function getDateReferrer() { return $this->dateReferrer; } /** * Setter setSearchReferrer. * * @since 1.0.0 * @param $searchReferrer * @return $this */ public function setSearchReferrer($searchReferrer) { $this->searchReferrer = $searchReferrer; return $this; } /** * Returns the value of the $searchReferrer property. * * @since 1.0.0 * @return (array) $this->searchReferrer */ public function getSearchReferrer() { return $this->searchReferrer; } /** * Setter setTaxReferrer. * * @since 1.0.0 * @param $taxReferrer * @return $this */ public function setTaxReferrer($taxReferrer) { $this->taxReferrer = $taxReferrer; return $this; } /** * Returns the value of the $taxReferrer property. * * @since 1.0.0 * @return (array) $this->taxReferrer */ public function getTaxReferrer() { return $this->$taxReferrer; } /** * Test $authorReferrer against $superGlobalVar. * * @since 1.0.0 * @return (bool) true on success or false on failure */ public function isAuthorReferrer() { if ($this->authorReferrer && isset($this->superGlobalVar[$this->authorReferrer])) { $isAuthorReferrer = true; } else { $isAuthorReferrer = false; } return $isAuthorReferrer; } /** * Test $authorReferrer against $superGlobalVar * * @since 1.0.0 * @return (bool) true on success or false on failure */ public function isDateReferrer() { if ($this->dateReferrer && isset($this->superGlobalVar[$this->dateReferrer])) { $isDateReferrer = true; } else { $isDateReferrer = false; } return $isDateReferrer; } /** * Test $authorReferrer against $superGlobalVar. * * @since 1.0.0 * @return (bool) true on success or false on failure */ public function isSearchReferrer() { if ($this->searchReferrer && isset($this->superGlobalVar[$this->searchReferrer])) { $isSearchReferrer = true; } else { $isSearchReferrer = false; } return $isSearchReferrer; } /** * Test $authorReferrer against $superGlobalVar. * * @since 1.0.0 * @return (bool) true on success or false on failure */ public function isTaxReferrer() { if ($this->taxReferrer && isset($this->superGlobalVar[$this->taxReferrer])) { $isTaxReferrer = true; } else { $isTaxReferrer = false; } return $isTaxReferrer; } /** * Conditional which check if the current post is a referred post. * * @since 1.0.0 * @return (bool) true on success or false on failure */ public function isReferredPost() { if ($this->isAuthorReferrer() || $this->isDateReferrer() || $this->isSearchReferrer() || $this->isTaxReferrer()) { $isReferredPost = true; } else { $isReferredPost = false; } return $isReferredPost; } /** * Return the value from the super global when the current post is a post referred from * an author archive page. * * @since 1.0.0 * @return (array) $authorReferrerValue */ public function hasAuthorReferrerValue() { if ($this->isAuthorReferrer()) { $authorReferrerValue = [$this->authorReferrer => $this->superGlobalVar[$this->authorReferrer]]; } else { $authorReferrerValue = null; } return $authorReferrerValue; } /** * Return the value from the super global when the current post is a post referred from * a date archive page. * * @since 1.0.0 * @return (array) $dateReferrerValue */ public function hasDateReferrerValue() { if ($this->isDateReferrer()) { $dateReferrerValue = [$this->dateReferrer => $this->superGlobalVar[$this->dateReferrer]]; } else { $dateReferrerValue = null; } return $dateReferrerValue; } /** * Return the value from the super global when the current post is a post referred from * a search page. * * @since 1.0.0 * @return (array) $searchReferrerValue */ public function hasSearchReferrerValue() { if ($this->isSearchReferrer()) { $searchReferrerValue = [$this->searchReferrer => $this->superGlobalVar[$this->searchReferrer]]; } else { $searchReferrerValue = null; } return $searchReferrerValue; } /** * Return the value from the super global when the current post is a post referred from * a taxonomy archive page. * * @since 1.0.0 * @return (array) $taxReferrerValue */ public function hasTaxReferrerValue() { if ($this->isTaxReferrer()) { $taxReferrerValue = [$this->taxReferrer => $this->superGlobalVar[$this->taxReferrer]]; } else { $taxReferrerValue = null; } return $taxReferrerValue; } } 

Вот как я использую этот класс

 $b = new RequestReferrerHandler($_GET, 'aq', 'dq', 'sq', 'tq'); ?><pre><?php var_dump($b->hasAuthorReferrerValue()); ?></pre><?php ?><pre><?php var_dump($b->hasDateReferrerValue()); ?></pre><?php ?><pre><?php var_dump($b->hasSearchReferrerValue()); ?></pre><?php ?><pre><?php var_dump($b->hasTaxReferrerValue()); ?></pre><?php 

Для целей тестирования вы можете ввести в класс нечто вроде ['aq' => '1'] вместо $_GET

Здесь я застрял и понятия не имею, как двигаться дальше. Мне нужно построить два класса, которые будут использовать те же методы из вышеприведенного класса, один класс, который будет строить аргументы запроса из методов has* из вышеприведенного класса, а один класс будет создавать query_vars также из методов has* из приведенного выше класс, который будет использоваться для создания новых сообщений

Короче говоря, оба класса будут использовать то же самое для методов из вышеуказанного класса

 hasAuthorReferrerValue(); hasDateReferrerValue(); hasSearchReferrerValue(); hasTaxReferrerValue(); 

Как пример, вот пример того, как должны выглядеть два класса. ( Я пропустил некоторые из методов здесь, чтобы сделать код более управляемым )

ClassA

 <?php namespace PG\Single\Post\Navigation; class ClassA //Just a generic name for testing purposes. Will also implement ClassAInterface { protected $handler; public function __construct(RequestReferrerHandlerInterface $handler) { $this->handler = $handler; } public function santizeAuthor() { $author = $this->handler->hasAuthorReferrerValue(); // Value will be either null or single key/value pair array. Example ['aq' => '1'] if ($author) { $author = array_values($author); $author = ['author' => (int)htmlspecialchars($author[0])]; //Will output ['author' => 1] } return $author; //Returns null or the array ['author' => 1] } public function santizeDate() { $date = $this->handler->hasDateReferrerValue(); if ($date) { // @TODO Still to work out } return $date; } //etc public function queryArguments() // Will be used in the controller class ClassC { $queryArgs = null; if ($this->santizeAuthor()) { $queryArgs = $this->santizeAuthor(); } elseif ($this->santizeDate) { $queryArgs = $this->santizeDate(); } // etc return $queryArgs; //Will return null if all 4 conditions fail or return the value from the one that returns true } } 

ClassB

 <?php namespace PG\Single\Post\Navigation; class ClassB //Just a generic name for testing purposes. Will also implement ClassBInterface { protected $handler; public function __construct(RequestReferrerHandlerInterface $handler) { $this->handler = $handler; } public function santizeAuthor() { $author = $this->handler->hasAuthorReferrerValue(); // Value will be either null or single key/value pair array. Example ['aq' => '1'] if ($author) { foreach ($author as $k=>$v) $author[htmlspecialchars($k)] = (int)htmlspecialchars($v); } return $author; //Returns null or the array ['aq' => 1] } public function santizeDate() { $date = $this->handler->hasDateReferrerValue(); if ($date) { // @TODO Still to work out } return $date; } //etc public function queryVars() // Will be used in the controller class ClassC { $queryVars = null; if ($this->santizeAuthor()) { $queryVars = $this->santizeAuthor(); } elseif ($this->santizeDate) { $queryVars = $this->santizeDate(); } // etc return $queryVars; //Will return null if all 4 conditions fail or return the value from the one that returns true } } 

Метод queryArguments() ClassA и queryVars() класса ClassB будет использоваться в других классах (или одном классе контроллера)

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

В любом случае, я могу оптимизировать вышеупомянутое. Я не прошу переписать код какого-либо типа, все, что мне нужно, – это правильные указатели и идеи по оптимизации этого, чтобы довести его до стандартного, если это не так. Это было бы настоящим плюсом, если бы кто-нибудь мог дать образцы кода, что-то вроде каркаса схемы

Оглядываясь на свой код, вы, безусловно, хорошо себя чувствуете. Вы уже используете одно правильное правило при программировании в ООП- программе для интерфейса, а не в реализации. Термин « интерфейс» я имею в виду не только для реальных интерфейсов, но и для абстрактных классов.

Поэтому в основе вашего вопроса вы хотите иметь два класса, ClassA и ClassB которые используют общие методы из RequestReferrerHandler . У вас уже есть работа, RequestReferrerHandlerInterface на работе с вашим интерфейсом RequestReferrerHandlerInterface . Поэтому мы скажем, что у вас есть интерфейс, который выглядит так:

 interface RequestReferrerHandlerInterface { public function hasAuthorReferrerValue(); public function hasDateReferrerValue(); public function hasSearchReferrerValue(); public function hasTaxReferrerValue(); } 

Пока этот интерфейс реализуется RequestReferrerHandler вы можете ввести подсказку интерфейса как требования к конструктору для ClassA и ClassB . Но это не ново, потому что вы уже делали это.

В частности, есть две особенности, которые выделяются во мне как потенциальные больные пальцы. Во-первых, поскольку вы хотите, чтобы обязанности ваших классов были небольшими, вы должны взять на себя ответственность за предоставление данных в RequestReferrerHandler от себя и передать его своему Controller . Другими словами, не вводите $_GET в свой класс. Убедитесь, что ваш Controller имеет всю необходимую информацию для правильного создания RequestReferrerHandler Давайте посмотрим на ваш класс RequestReferrerHandler , RequestReferrerHandler всеми методами, которые ему понадобятся.

 class RequestReferrerHandler implements RequestReferrerHandlerInterface { private $author; private $date; private $search; private $tax; public function __construct($author = null, $date = null, $search = null, $tax = null) { $this->setAuthorReferrer($author); $this->setDateReferrer($date); $this->setSearchReferrer($search); $this->setTaxReferrer($tax); } public function hasAuthorReferrerValue() { return $this->author !== null ? true : false; } public function hasDateReferrerValue() { return $this->date !== null ? true : false; } public function hasSearchReferrerValue() { return $this->search !== null ? true : false; } public function hasTaxReferrerValue() { return $this->tax !== null ? true : false; } public function getAuthorReferrer() { return $this->author; } public function getDateReferrer() { return $this->date; } public function getSearchReferrer() { return $this->search; } public function getTaxReferrer() { return $this->tax; } public function setAuthorReferrer($author) { $this->author = $author; } public function setDateReferrer($date) { $this->date = $date; } public function setSearchReferrer($search) { $this->search = $search; } public function setTaxReferrer($tax) { $this->tax = $tax; } } 

Вторая вещь, которая торчит, – это santize() . Вы видите, как они дублируются как в ClassA и в ClassB ? sanitizeAuthor() отличается от двух классов, но как насчет остальных? Это случай, когда принцип DRY (Do not Repeat Yourself) может помочь. Поскольку нескольким классам, возможно, придется санировать данные аналогичным образом, имеет смысл абстрагировать это от ваших классов.

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

 interface SanitizerInterface { public function sanitizeAuthor(); public function sanitizeDate(); public function sanitizeSearch(); public function sanitizeTaxonomy(); } 

Теперь, если каждый объект, который вы имели в ClassX реализовал эти четыре метода по-разному, вы можете начать его реализацию в разных классах, которые просто дезинфицируют данные. Однако в этом примере мы скажем, что это не так. Предположим, что sanitizeAuthor() может отличаться от ClassA и ClassB (который находится в вашем коде), и все остальные методы будут реализованы точно так же. Это случай, когда мы можем использовать абстрактный класс, который будет реализовывать методы дезинфицирующих средств.

 abstract class AbstractSanitizer implements SanitizerInterface { protected $handler; public function __construct() {} public function setHandler(RequestReferrerHandlerInterface $handler) { $this->handler = $handler; } /* For this example we are saying that sanitizeDate(), sanitizeTaxonomy() and * sanitizeSearch() will be the same no matter what. So let's implement them * and leave the child classes to implement sanitizeAuthor(). * * Implement the details of the sanitizer function to fit your needs. */ public function sanitizeDate() { if($this->handler !== null) { //Perform whatever tasks to sanitize the date $sanitized = strtoupper($this->handler->getDateReferrer()); echo "Sanitize date -> switch to uppercase letters.\n"; $this->handler->setDateReferrer($sanitized); } } public function sanitizeSearch() { if($this->handler !== null) { //Perform whatever tasks to sanitize the search $sanitized = strtolower($this->handler->getSearchReferrer()); echo "Sanitize search -> switch to lowercase letters.\n"; $this->handler->setSearchReferrer($sanitized); } } public function sanitizeTaxonomy() { if($this->handler !== null) { //Perform whatever tasks to sanitize the taxonomy $sanitized = str_replace(" ", "_", $this->handler->getTaxReferrer()); echo "Sanitize Taxonomy -> convert spaces to underscores.\n"; $this->handler->setTaxReferrer($sanitized); } } } 

Некоторые вещи, чтобы принять во внимание прямо с места в карьер. Во-первых, вы заметите, что существует метод setHandler() который принимает экземпляр RequestReferrerHandlerInterface . Почему это? Удобство по большей части. Поскольку мы взяли санирующее поведение и инкапсулировали его в свой класс, было бы неплохо, если бы мы дали sanitizer способ обновить конкретный RequestReferrerHandler он использует с обновленным результатом метода sanitize.

Далее мы используем методы из класса RequestReferrerHandler , которые не указаны в RequestReferrerHandlerInterface . Это не является непосредственной проблемой как таковой , потому что мы знаем, что методы, подобные геттерам и сеттерам, относятся к классу. Однако тип намека на интерфейс сам по себе не гарантирует, что эти методы будут доступны, если вы когда-либо решили реализовать этот интерфейс с другим конкретным объектом. Поэтому нам необходимо обновить RequestReferrerHandlerInterface с помощью методов, которые гарантируют их доступность.

 interface RequestReferrerHandlerInterface { public function hasAuthorReferrerValue(); public function hasDateReferrerValue(); public function hasSearchReferrerValue(); public function hasTaxReferrerValue(); public function getAuthorReferrer(); public function getDateReferrer(); public function getSearchReferrer(); public function getTaxReferrer(); public function setAuthorReferrer($author); public function setDateReferrer($date); public function setSearchReferrer($search); public function setTaxReferrer($tax); } 

Теперь вернемся к тем дезинфицирующим средствам. Мы знаем, что ClassA и ClassB будут применять методы sanitizeAuthor() разному. Абстрактный класс AbstractSanitizer был сделан так, как это было сделано потому, что метод sanitizeAuthor() из SanitizerInteface не реализован в AbstractSanitizer поэтому мы должны расширить его, чтобы обеспечить функциональность. Для этого нам понадобятся следующие два класса:

 class SanitizerForClassA extends AbstractSanitizer { /* This class must provide an implementation for how ClassA will * handle the sanitizeAuthor() method. */ public function sanitizeAuthor() { if($this->handler !== null) { //Perform whatever tasks to sanitize the for ClassA $sanitized = array("author" => $this->handler->getAuthorReferrer()); echo "Sanitize author -> ClassA makes author an array.\n"; $this->handler->setAuthorReferrer($sanitized); } } } class SanitizerForClassB extends AbstractSanitizer { /* This class must provide an implementation for how ClassB will * handle the sanitizeAuthor() method. */ public function sanitizeAuthor() { if($this->handler !== null) { //Perform whatever tasks to sanitize the for ClassB $sanitized = new stdClass(); $sanitized->author = $this->handler->getAuthorReferrer(); echo "Sanitize author -> ClassB makes author an object property. \n"; $this->handler->setAuthorReferrer($sanitized); } } } 

Эти два конкретных класса могут использоваться с ClassA и ClassB для дезинфекции данных в конкретных методах RequestReferrerHandler которые будут переданы в них.

Итак, перейдем к рассмотрению спецификации для ClassA и ClassB . Мы знаем, что ClassA понадобится метод queryArguments() , ClassB будет нужен метод queryVars() и оба класса должны будут разрешать и экземпляр RequestReferrerHandlerInterface и SanitizerInterface в своих конструкторах. Мы будем обрабатывать требование конструктора с помощью одного интерфейса, а затем два других интерфейса будут расширять его, чтобы обеспечить все требования к методу, необходимые для ClassA и ClassB .

 interface SanitizableHandlerInterface { public function __construct(RequestReferrerHandlerInterface $handler, SanitizerInterface $sanitizer); } interface QueryVarsInterface extends SanitizableHandlerInterface { public function queryVars(); } interface QueryArgumentsInterface extends SanitizableHandlerInterface { public function queryArguments(); } 

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

 class ClassA implements QueryArgumentsInterface { private $handler; private $sanitizer; public function __construct(RequestReferrerHandlerInterface $handler, SanitizerInterface $sanitizer) { $this->handler = $handler; $this->sanitizer = $sanitizer; $this->sanitizer->setHandler($this->handler); } public function queryArguments() // Will be used in the controller class ClassC { $queryArgs = null; if($this->handler->hasAuthorReferrerValue()) { $this->sanitizer->sanitizeAuthor(); $queryArgs = $this->handler->getAuthorReferrer(); } if($this->handler->hasDateReferrerValue()) { $this->sanitizer->sanitizeDate(); $queryArgs = $this->handler->getDateReferrer(); } if($this->handler->hasSearchReferrerValue()) { $this->sanitizer->sanitizeSearch(); $queryArgs = $this->handler->getSearchReferrer(); } if($this->handler->hasTaxReferrerValue()) { $this->sanitizer->sanitizeTaxonomy(); $queryArgs = $this->handler->getTaxReferrer(); } return $queryArgs; //Will return null if all 4 conditions fail or return the value from the one that returns true } } class ClassB implements QueryVarsInterface { private $handler; private $sanitizer; public function __construct(RequestReferrerHandlerInterface $handler, SanitizerInterface $sanitizer) { $this->handler = $handler; $this->sanitizer = $sanitizer; $this->sanitizer->setHandler($this->handler); } public function queryVars() // Will be used in the controller class ClassC { $queryVars = null; if($this->handler->hasAuthorReferrerValue()) { $this->sanitizer->sanitizeAuthor(); $queryVars = $this->handler->getAuthorReferrer(); } if($this->handler->hasDateReferrerValue()) { $this->sanitizer->sanitizeDate(); $queryVars = $this->handler->getDateReferrer(); } if($this->handler->hasSearchReferrerValue()) { $this->sanitizer->sanitizeSearch(); $queryVars = $this->handler->getSearchReferrer(); } if($this->handler->hasTaxReferrerValue()) { $this->sanitizer->sanitizeTaxonomy(); $queryVars = $this->handler->getTaxReferrer(); } return $queryVars; //Will return null if all 4 conditions fail or return the value from the one that returns true } } 

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

Итак, вопрос в миллион долларов заключается в том, как использовать это. Ну, вам нужен контроллер, который может принимать ClassA и ClassB . Мы будем набирать намеки на их соответствующие интерфейсы.

 class Controller { public function __construct() {} public function doStuff(QueryArgumentsInterface $argsClass, QueryVarsInterface $varsClass) { var_dump($argsClass->queryArguments()); var_dump($varsClass->queryVars()); } } 

В вашей версии queryArguments() и queryVars() вы ожидали, что данные будут queryVars() для возвращаемого значения. Давайте подключим некоторые данные и посмотрим, что получим. (Примечание. Как вы уже выяснили, ни один из методов санитарии, которые я использовал, не делает то, что вы делаете, они только иллюстративные.)

 //TEST DRIVE //Create a controller that will use the classes $controller = new Controller(); //Now make use of your new shiny handlers and sanitizers $controller->doStuff( new ClassA(new RequestReferrerHandler("Mark Twain", null, null, null), new SanitizerForClassA()), new ClassB(new RequestReferrerHandler(null, "January 1st, 1999", null, null), new SanitizerForClassB()) ); $controller->doStuff( new ClassA(new RequestReferrerHandler(null, null, "OK Google Now!", null), new SanitizerForClassA()), new ClassB(new RequestReferrerHandler(null, null, null, "Super Awesome Taxonomy Tables"), new SanitizerForClassB()) ); $controller->doStuff( new ClassA(new RequestReferrerHandler(null, "January 1st, 1999", null, null), new SanitizerForClassA()), new ClassB(new RequestReferrerHandler("Mark Twain", null, null, null), new SanitizerForClassB()) ); $controller->doStuff( new ClassA(new RequestReferrerHandler(null, null, null, "Super Awesome Taxonomy Tables"), new SanitizerForClassA()), new ClassB(new RequestReferrerHandler(null, null, "OK Google Now!", null), new SanitizerForClassB()) ); 

Вот результат:

 Sanitize author -> ClassA makes author an array. array (size=1) 'author' => string 'Mark Twain' (length=10) Sanitize date -> switch to uppercase letters. string 'JANUARY 1ST, 1999' (length=17) Sanitize search -> switch to lowercase letters. string 'ok google now!' (length=14) Sanitize Taxonomy -> convert spaces to underscores. string 'Super_Awesome_Taxonomy_Tables' (length=29) Sanitize date -> switch to uppercase letters. string 'JANUARY 1ST, 1999' (length=17) Sanitize author -> ClassB makes author an object property. object(stdClass)[15] public 'author' => string 'Mark Twain' (length=10) Sanitize Taxonomy -> convert spaces to underscores. string 'Super_Awesome_Taxonomy_Tables' (length=29) Sanitize search -> switch to lowercase letters. string 'ok google now!' (length=14) 

Так что же все это стоило вам? Короткий ответ – сложность. Для вывода небольшого количества данных на экран потребовалось 4 интерфейса, 1 абстрактный класс и несколько конкретных классов.

Что вы получаете? Короткий ответ – гибкость. В будущем вы можете добавить еще несколько классов, которые реализуют QueryVarsInterface или QueryArgumentsInterface . Рассмотрим эти классы ClassC , ClassD и ClassE . Все эти классы нуждаются в классе дезинфицирующих средств, чтобы пойти с ними (то есть, если SanitizerForClassA или SanitizerForClassB не соответствуют законопроекту), и было бы утомительно продолжать писать классы дезинфицирующих средств. Хорошо, хорошо для вас, поскольку вы все время программировали интерфейс , у вас не будет этой проблемы. Вы можете легко создать GenericSanitizer с реализацией метода sanitizeAuthor() по умолчанию. Использование может использовать этот класс с помощью Controller::doStuff() в любом случае, когда вам не нужен специализированный класс дезинфицирующих средств. Вы могли бы легко реализовать различные конкретные классы QueryArgumentInterface или QueryVarsInterface для тестирования экспериментальных функций, которые вы хотите добавить, без вмешательства в ваши текущие классы.

Надеюсь, это дало вам некоторое представление о некоторых принципах ООП. Вот полная копия всего кода выше. Поместите это в пустой файл PHP и запустите его, чтобы увидеть все в действии. Счастливое программирование!

  <?php /* * INTERFACES */ interface RequestReferrerHandlerInterface { public function hasAuthorReferrerValue(); public function hasDateReferrerValue(); public function hasSearchReferrerValue(); public function hasTaxReferrerValue(); public function getAuthorReferrer(); public function getDateReferrer(); public function getSearchReferrer(); public function getTaxReferrer(); public function setAuthorReferrer($author); public function setDateReferrer($date); public function setSearchReferrer($search); public function setTaxReferrer($tax); } interface SanitizerInterface { public function sanitizeAuthor(); public function sanitizeDate(); public function sanitizeSearch(); public function sanitizeTaxonomy(); } interface SanitizableHandlerInterface { public function __construct(RequestReferrerHandlerInterface $handler, SanitizerInterface $sanitizer); } interface QueryVarsInterface extends SanitizableHandlerInterface { public function queryVars(); } interface QueryArgumentsInterface extends SanitizableHandlerInterface { public function queryArguments(); } /* * ABSTRACT CLASSES */ abstract class AbstractSanitizer implements SanitizerInterface { protected $handler; public function __construct() {} public function setHandler(RequestReferrerHandlerInterface $handler) { $this->handler = $handler; } /* For this example we are saying that sanitizeDate(), sanitizeTaxonomy() and * sanitizeSearch() will be the same no matter what. So let's implement them * and leave the child classes to implement sanitizeAuthor(). * * Implement the details of the sanitizer function to fit your needs. */ public function sanitizeDate() { if($this->handler !== null) { //Perform whatever tasks to sanitize the date $sanitized = strtoupper($this->handler->getDateReferrer()); echo "Sanitize date -> switch to uppercase letters.\n"; $this->handler->setDateReferrer($sanitized); } } public function sanitizeSearch() { if($this->handler !== null) { //Perform whatever tasks to sanitize the search $sanitized = strtolower($this->handler->getSearchReferrer()); echo "Sanitize search -> switch to lowercase letters.\n"; $this->handler->setSearchReferrer($sanitized); } } public function sanitizeTaxonomy() { if($this->handler !== null) { //Perform whatever tasks to sanitize the taxonomy $sanitized = str_replace(" ", "_", $this->handler->getTaxReferrer()); echo "Sanitize Taxonomy -> convert spaces to underscores.\n"; $this->handler->setTaxReferrer($sanitized); } } } /* * CONCRETE CLASSES */ class RequestReferrerHandler implements RequestReferrerHandlerInterface { private $author; private $date; private $search; private $tax; public function __construct($author = null, $date = null, $search = null, $tax = null) { $this->setAuthorReferrer($author); $this->setDateReferrer($date); $this->setSearchReferrer($search); $this->setTaxReferrer($tax); } public function hasAuthorReferrerValue() { return $this->author !== null ? true : false; } public function hasDateReferrerValue() { return $this->date !== null ? true : false; } public function hasSearchReferrerValue() { return $this->search !== null ? true : false; } public function hasTaxReferrerValue() { return $this->tax !== null ? true : false; } public function getAuthorReferrer() { return $this->author; } public function getDateReferrer() { return $this->date; } public function getSearchReferrer() { return $this->search; } public function getTaxReferrer() { return $this->tax; } public function setAuthorReferrer($author) { $this->author = $author; } public function setDateReferrer($date) { $this->date = $date; } public function setSearchReferrer($search) { $this->search = $search; } public function setTaxReferrer($tax) { $this->tax = $tax; } } class SanitizerForClassA extends AbstractSanitizer { /* This class must provide an implementation for how ClassA will * handle the sanitizeAuthor() method. */ public function sanitizeAuthor() { if($this->handler !== null) { //Perform whatever tasks to sanitize the for ClassA $sanitized = array("author" => $this->handler->getAuthorReferrer()); echo "Sanitize author -> ClassA makes author an array.\n"; $this->handler->setAuthorReferrer($sanitized); } } } class SanitizerForClassB extends AbstractSanitizer { /* This class must provide an implementation for how ClassB will * handle the sanitizeAuthor() method. */ public function sanitizeAuthor() { if($this->handler !== null) { //Perform whatever tasks to sanitize the for ClassB $sanitized = new stdClass(); $sanitized->author = $this->handler->getAuthorReferrer(); echo "Sanitize author -> ClassB makes author an object property. \n"; $this->handler->setAuthorReferrer($sanitized); } } } class ClassA implements QueryArgumentsInterface { private $handler; private $sanitizer; public function __construct(RequestReferrerHandlerInterface $handler, SanitizerInterface $sanitizer) { $this->handler = $handler; $this->sanitizer = $sanitizer; $this->sanitizer->setHandler($this->handler); } public function queryArguments() // Will be used in the controller class ClassC { $queryArgs = null; if($this->handler->hasAuthorReferrerValue()) { $this->sanitizer->sanitizeAuthor(); $queryArgs = $this->handler->getAuthorReferrer(); } if($this->handler->hasDateReferrerValue()) { $this->sanitizer->sanitizeDate(); $queryArgs = $this->handler->getDateReferrer(); } if($this->handler->hasSearchReferrerValue()) { $this->sanitizer->sanitizeSearch(); $queryArgs = $this->handler->getSearchReferrer(); } if($this->handler->hasTaxReferrerValue()) { $this->sanitizer->sanitizeTaxonomy(); $queryArgs = $this->handler->getTaxReferrer(); } return $queryArgs; //Will return null if all 4 conditions fail or return the value from the one that returns true } } class ClassB implements QueryVarsInterface { private $handler; private $sanitizer; public function __construct(RequestReferrerHandlerInterface $handler, SanitizerInterface $sanitizer) { $this->handler = $handler; $this->sanitizer = $sanitizer; $this->sanitizer->setHandler($this->handler); } public function queryVars() // Will be used in the controller class ClassC { $queryVars = null; if($this->handler->hasAuthorReferrerValue()) { $this->sanitizer->sanitizeAuthor(); $queryVars = $this->handler->getAuthorReferrer(); } if($this->handler->hasDateReferrerValue()) { $this->sanitizer->sanitizeDate(); $queryVars = $this->handler->getDateReferrer(); } if($this->handler->hasSearchReferrerValue()) { $this->sanitizer->sanitizeSearch(); $queryVars = $this->handler->getSearchReferrer(); } if($this->handler->hasTaxReferrerValue()) { $this->sanitizer->sanitizeTaxonomy(); $queryVars = $this->handler->getTaxReferrer(); } return $queryVars; //Will return null if all 4 conditions fail or return the value from the one that returns true } } class Controller { public function __construct() {} public function doStuff(QueryArgumentsInterface $argsClass, QueryVarsInterface $varsClass) { var_dump($argsClass->queryArguments()); var_dump($varsClass->queryVars()); } } /* * TEST DRIVE */ //Create a controller that will use the classes $controller = new Controller(); //Now make use of your new shiny handlers and sanitizers $controller->doStuff( new ClassA(new RequestReferrerHandler("Mark Twain", null, null, null), new SanitizerForClassA()), new ClassB(new RequestReferrerHandler(null, "January 1st, 1999", null, null), new SanitizerForClassB()) ); $controller->doStuff( new ClassA(new RequestReferrerHandler(null, null, "OK Google Now!", null), new SanitizerForClassA()), new ClassB(new RequestReferrerHandler(null, null, null, "Super Awesome Taxonomy Tables"), new SanitizerForClassB()) ); $controller->doStuff( new ClassA(new RequestReferrerHandler(null, "January 1st, 1999", null, null), new SanitizerForClassA()), new ClassB(new RequestReferrerHandler("Mark Twain", null, null, null), new SanitizerForClassB()) ); $controller->doStuff( new ClassA(new RequestReferrerHandler(null, null, null, "Super Awesome Taxonomy Tables"), new SanitizerForClassA()), new ClassB(new RequestReferrerHandler(null, null, "OK Google Now!", null), new SanitizerForClassB()) ); 

As I can see in your previous questions , you look for a way to rationalize your OOP development. This is why I won't give you a fish but I will help you to fish by yourself. This means that I'm gonna (try to) give the base that you should know to do a strong OOP code.

1. SRP and composition

As I can see in your questions, you try to separate responsability of your classes. This is a good thing in OOP of course. What you do is called Single Responsability Principle (SRP) . This principle imply that you prefer composition over inheritance.

 // Composition class Car implements VehicleInterface { private $motor; } class Motor implements MotorInterface 

In this case, the car and the motor have 2 different responsabilities.

 // Inheritance class Car extends MotorVehicle { } 

In the case of inheritance, you make a high compling between the vehicle and motor notions.

Imagine I want to had a new notion like the movement for example:

 // Composition class Car implements VehicleInterface { private $motor; private $movement; } class Motor implements MotorInterface class Drive implements MovementInterface 

No problem with composition.

 // Inheritance class Car extends MotorVehicle, DriveVehicle { } 

Multiple inheritance is bad (and even not possible in PHP) because you break the SRP. Inheritance should only be used for factoring code for classes of the same responsability. As you should have only one responsability by class, you shouldn't use multiple inheritance. Other possibilities are bad because you cannot tell me that a Car is more a MotorVehicle than a DriveVehicle .

In your case, you have some request referrer handlers and some sanitizer .

2. Interfaces and low coupling

As I told you in my previous answer your do right when using interfaces to make a low coupling between your classes. This give you a more maintenable, scalable and testable code. Take the previous example:

 class Car implements VehicleInterface { private $motor; } class PetrolMotor implements MotorInterface class DieselMotor implements MotorInterface 

Your car can easily take different kind of motors now!

The idea that should drive your mind here, is that a class should never use another class directly but an interface describing a behaviour.

In your case, class A and class B should implement an interface SanitizerInterface .

3. Dependency Injection

At this point, you want to set your handlers in your sanitizer. The better way is to use dependency injection . This is really simple!

 class Car implements VehicleInterface { private $motor; public function __construct(MotorInterface $motor) { $this->motor = $motor; } } class PetrolMotor implements MotorInterface { } class DieselMotor implements MotorInterface { } $motor = new PetrolMotor(); $car = new Car($motor); 

In your case, you have to inject the request referrer handler in your sanitizer .

4. SOA

Service Oriented Architecture (SOA) applied to OOP is a great way to rationalize your code.

 // Standard OOP $car = new Car(); $buyer = new Person(); $store = new Store(); // Many solutions to buy a car! $buyer->buy($car, $store); // or $store->sell($car, $buyer); // or // ... 

In standard OOP, you are often confronted to duplicated code because of that. Where should I code this method? Where I can now where I (or someone else) already coded this method? This problem was so boring for me before! I was not able to rationalize my development.

 // SOA $car = new Car(); $buyer = new Person(); $store = new Store(); $saleHandler = new SaleHandler(); $saleHandler->sell($car, $buyer, $store); 

In SOA, you have a "service class" (here SaleHandler ) (basically implemented as a singleton ) which handle the maniplation of "data classes" (here Car , Person and Store ). There is no intelligence in your data classes (you often only have getters and setters on properties). This way, you know where is your code for sales!

In your case, it seems that your request referrer handlers and sanitizers are some kind of services, so it's ok.

Вывод

In conclusion, you use intuitively some really good OOP practices. Now, you can apply them and know why!

However, I would highly advice you to try a framework like Symfony2 . It will provide you with a strong base for you PHP development and a really nice dependency injection component allowing you to define all the dependencies of your classes in configuration files to have a real dynamical code. It will also help you to do SOA with its services.

Using a framework is a good thing to power up your developments and for your professional life (a developer knowing a framework is a lot more sought after). As PHP frameworks are mainly opensource, you can also participate and give you a nice visibility for recruiters.

If you want to use the same object of RequestReferrerHandler class to ClassA and ClassB, then your strategy is correct. Just need to use the object of RequestReferrerHandler class to instantiate ClassA and ClassB. Then you can access the particular methods. ie ClassA.queryArguments() or ClassB.queryVars()

If you want to create seperate object of RequestReferrerHandler class for ClassA and ClassB, you can extend RequestReferrerHandler class to ClassA and ClassB without defining the constructor. So, when you create object of ClassA, it automatically inherit the constructor method of RequestReferrerHandler class and you can access the property and method by parent: keyword. Например:

 class ClassA extends RequestReferrerHandler { public function santizeAuthor() { $author = parent::hasAuthorReferrerValue(); // access the base class method if ($author) { $author = array_values($author); $author = ['author' => (int)htmlspecialchars($author[0])]; //Will output ['author' => 1] } return $author; //Returns null or the array ['author' => 1] } public function santizeDate() { $date = parent::hasDateReferrerValue(); if ($date) { // @TODO Still to work out } return $date; } //etc public function queryArguments() // Will be used in the controller class ClassC { $queryArgs = null; if ($this->santizeAuthor()) { $queryArgs = $this->santizeAuthor(); } elseif ($this->santizeDate) { $queryArgs = $this->santizeDate(); } // etc return $queryArgs; //Will return null if all 4 conditions fail or return the value from the one that returns true } } 

You can do as same as for ClassB. Now you can create object for ClassA and ClassB assigning the constructor's argument of their base class in Class C and use the return value of ClassA.queryArguments() or ClassB.queryVars() from their object.

This problem can be simplified if you concentrated in the type of data instead of the meaning of the objects i were working in a api that is able to manipulate and get information from the WordPress structure and i know that they already did a very nice job simplifying their data structure. so you only have to think in therms of post, post meta, and taxonomies (index) and not in meanings like (publication, tax, image, library, post, product).

Even in woo commerce you can see it that is very simple.

You would see that; a product is a type of post, that the data of the product is in post meta. a image is a type of post and the details of that image is in post_meta, that a news is a post and the details of this news s in post meta.

One structure different meaning. So for access everything or store data for everything you only need this elements. if you have access to this elements in a restful way the implementation is very easy to.

I hope this help you some how is just my point of view you can think otherwise. but i thought was important to share his with you.