Я пытаюсь построить свою собственную инфраструктуру MVC (конечно, чтобы узнать ее лучше), следуя последнему шаблону проектирования ООП. Мне было интересно, какова лучшая практика для размещения повторяемых кодов (которые используются, чтобы оставаться в служебных классах как статические методы, которые считают не очень хорошими шаблонами).
Например, мы хотим обойти многомерный массив, используя разделенную точками строку, и я должен использовать этот алгоритм в нескольких классах (которые являются подклассами из других базовых классов). Как я могу сделать это, не используя служебный класс и не повторяя один и тот же код несколько раз?
В классе утилит нет ничего плохого, просто не объединяйте все свои несвязанные функции утилит в один гигантский класс. Разделите (и пространство имен) их тем, что они делают. Например, см. Zend Filter или же Файловая система Symfony.
В качестве альтернативы, если классы, которым нужна эта функция, имеют общего родителя, вы можете поместить функцию в самый верхний класс или реферат.
Или, если у классов нет общего родителя, вы можете создать черту с помощью метода extractArrayFromDottedString()
или похожие.
Если это служебные функции, определите их как таковые в отдельном пространстве имен. Что-то похожее на
<?php
namespace Utils;
function array_query($array, $query) {
// code for traversing the array
}
Поместите их в один или несколько файлов, и все будет в порядке. Просто не забудьте включить этот файл на этапе boostrap вашего приложения.
Нижняя линия: прекрати злоупотреблять статическими классами, теперь у нас есть пространства имен для этого дерьма.
Но не все из того, что вы считаете «служебными функциями», на самом деле. Часть кода, если вы начинаете использовать код ООП, должна идти в связанных классах. Например, «проверка электронной почты» должна идти не в «служебной функции», а в классе:
class EmailAddress {
private $emailAddress;
public function __construct($emailAddress) {
$this->assertValidEmailAddress($emailAddress);
$this->emailAddress = $emailAddress;
}
private function assertValidEmailAddress($emailAddress) {
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
throw new DomainException("Not an email address");
}
}
public function __toString() {
return $this->emailAddress;
}
}
И такие повторяющиеся фрагменты «доменной логики» должны идти в виде отдельных сущностей, которые затем вы можете напечатать для других классов. Тогда вы используете это где-то как:
public function register(EmailAddress $email, SafePassword $password): User
{
// your user registration logic
}
Таким образом, различные ваши службы могут выполнять действия, и вы используете try-catch
для улучшения проверки.
Постскриптум
Возможно, вам придется внимательно посмотреть на то, что вы делаете. Эта утилита с точечным доступом аккуратна (у меня она тоже была 10 лет назад), но на самом деле это «временное решение» для более глубокой проблемы: вам не нужно иметь дело с таким глубоким массивом, что вам нужно упростить доступ к ним.
Утилита класс анти-шаблон
Точно нет.
В ООП проектирование всего приложения с помощью служебных классов, скорее всего, является антишаблоном, но определение служебных классов с static
методы, которые обеспечивают рутинные / поперечные задачи, могут иметь смысл.
Отсутствие смешения утилитарных методов с методами существующих классов, которые их потребляют, может также обеспечить лучшую согласованность и возможность повторного использования класса утилит и потребительских классов.
Конечно, в качестве альтернативы вы можете определить класс с методами экземпляра.
Это действительно, более многословно, но имеет преимущество для улучшения тестируемости класса. Если вам нужно смоделировать вызовы или переключиться на другие реализации для служебных методов, следует использовать методы экземпляра.
Laravel делает это, определяя автономные «вспомогательные» функции. CakePHP и Yii делают это путем определения классов утилит контейнера (т. Е. «Text» или «Xml») статическими методами. Языки программирования делают подобные вещи (т.е. PHP implode()
Java Math.round
С strcpy
Питон sum()
, так далее.). Практически все используют либо автономные функции, либо методы статического класса.
В конечном итоге, лучший выбор субъективный. Это зависит от того, как вы хочу структурировать вещи. Исследуйте общие шаблоны проектирования в PHP и почувствуйте, как различные фреймворки чувствуются на практике. Затем выберите подход и оставайтесь последовательными.