Существует множество способов структурировать код и проект вашего веб-приложения, и вы можете уделять архитектуре столько внимания, сколько захотите. Но обычно полезно следовать общим шаблонам, потому что это поможет сделайте ваш код более простым в управлении и понятным для других.
Одним из наиболее часто используемых шаблонов проектирования является шаблон “Фабрика”. В этом шаблоне класс просто создает объект, который вы хотите использовать. Рассмотрим следующий пример шаблона фабрики:
<?php
class Automobile
{
private $vehicleMake;
private $vehicleModel;
public function __construct($make, $model)
{
$this->vehicleMake = $make;
$this->vehicleModel = $model;
}
public function getMakeAndModel()
{
return $this->vehicleMake . ' ' . $this->vehicleModel;
}
}
class AutomobileFactory
{
public static function create($make, $model)
{
return new Automobile($make, $model);
}
}
// have the factory create the Automobile object
$veyron = AutomobileFactory::create('Bugatti', 'Veyron');
print_r($veyron->getMakeAndModel()); // outputs "Bugatti Veyron"
Этот код использует фабрику для создания объекта Automobile. Есть два возможных преимущества для создания вашего кода этим способом; во-первых, если вам позже понадобится изменить, переименовать или заменить класс Automobile, вы сможете это сделать, и вам нужно будет изменить код только в фабрике, а не в каждом месте вашего проекта, где используется класс Automobile. Второе возможное преимущество заключается в том, что если создание объекта является сложной задачей, вы можете выполнить всю работу в Фабрике вместо того, чтобы повторять это каждый раз, когда вы хотите создать новый экземпляр.
Использование фабричного шаблона не всегда необходимо (или разумно). Используемый здесь пример кода настолько прост, что фабрика просто добавила бы ненужную сложность. Однако, если вы делаете довольно большой или сложный проект, вы можете избежать много неприятностей в будущем, используя фабрики.
При разработке веб-приложений часто имеет смысл концептуально и архитектурно разрешить доступ к одному и только одиному экземпляру определенного класса. Шаблон Одиночка (Singleton) позволяет нам сделать это.
TODO: NEED NEW SINGLETON CODE EXAMPLE
Приведенный выше код реализует шаблон Singleton с использованием static variable и статический метод создания getInstance()
.
Обратите внимание на следующее:
Конструктор __construct()
объявлен как protected для
для предотвращения создания нового экземпляра вне класса с помощью оператора new
.
__clone()
объявлен как private для предотвращения
клонирования экземпляра класса через метод clone
.__wakeup()
объявлен как private для предотвращения
десериализации экземпляра класса через глобальную функцию unserialize()
.getInstance()
с ключевым словом static
. Это позволяет создать подкласс класса Singleton
в
примере.Шаблон singleton полезен, когда нам нужно убедиться, что у нас есть только один экземпляр класса для всего жизненного цикла запроса в веб-приложении. Обычно это происходит, когда у нас есть глобальные объекты (например, класс конфигурации) или общий ресурс (например, очередь событий).
Вам следует быть осторожными при использовании шаблона Singleton, поскольку по своей природе он вводит глобальное состояние в ваше приложение, что снижает тестируемость. В большинстве случаев внедрение зависимостей (dependency injection) может (и должно) использоваться вместо Singleton. Использование внедрения зависимостей означает, что мы не вносим ненужную связанность в дизайн нашего приложения, поскольку объект, использующий общий или глобальный ресурс, не требует знания конкретно определенного класса.
С помощью шаблона стратегия вы инкапсулируете определенные семейства алгоритмов, позволяя клиентскому классу, отвечать за создание экземпляра конкретного алгоритма без знания фактической реализации. Существует несколько вариаций шаблона стратегии, самый простой из которых описан ниже:
В этом первом фрагменте кода описывается семейство алгоритмов; вам может понадобиться сериализованный массив, немного JSON или, может быть, просто массив данных:
<?php
interface OutputInterface
{
public function load();
}
class SerializedArrayOutput implements OutputInterface
{
public function load()
{
return serialize($arrayOfData);
}
}
class JsonStringOutput implements OutputInterface
{
public function load()
{
return json_encode($arrayOfData);
}
}
class ArrayOutput implements OutputInterface
{
public function load()
{
return $arrayOfData;
}
}
Инкапсулируя приведенные выше алгоритмы, вы делаете их красивыми и понятными в своем коде, чтобы другие разработчики могли легко добавлять новые типы вывода, не затрагивая клиентский код.
Вы увидите, как каждый конкретный “выходной” класс реализует OutputInterface — это служит двум целям: в первую очередь он обеспечивает простой контракт, которому должны подчиняться любые новые конкретные реализации. Во-вторых, реализовав общий интерфейс, который вы увидите в следующем разделе, который теперь можно использовать Type Hinting чтобы гарантировать, что клиент, который использует это поведение, имеет правильный тип в данном случае ‘OutputInterface’.
Следующий фрагмент кода показывает, как вызывающий клиентский класс может использовать один из этих алгоритмов и, что еще лучше, установить поведение, необходимое во время выполнения:
<?php
class SomeClient
{
private $output;
public function setOutput(OutputInterface $outputType)
{
$this->output = $outputType;
}
public function loadOutput()
{
return $this->output->load();
}
}
Вышеупомянутый класс вызывающий клиента, имеет приватное свойство, которое должно быть установлено во время выполнения и иметь тип «OutputInterface». Как только это свойство установлено, вызов loadOutput() вызовет метод load() в конкретном классе типа вывода. это было установлено.
Вызывающий клиентский класс выше, имеет приватное свойство, которое должно быть установлено во время выполнения и иметь тип ‘OutputInterface’ как только это свойство установлено для вызова loadOutput() который будет вызывать метод load() в конкретном классе типа вывода который был установлен.
<?php
$client = new SomeClient();
// Want an array?
$client->setOutput(new ArrayOutput());
$data = $client->loadOutput();
// Want some JSON?
$client->setOutput(new JsonStringOutput());
$data = $client->loadOutput();
Шаблон front controller — это единая точка входа для вашего веб-приложения (например, index.php), которая обрабатывает все запросы. Этот код отвечает за загрузку всех зависимостей, обработку запроса и отправку ответа в браузер. Шаблон front controller может быть полезен, поскольку он поощряет модульный код и дает вам центральное место для подключения кода, который должен выполняться для каждого запроса (например, для очистки ввода).
Шаблон модель-представление-контроллер (MVC) и его родственники HMVC и MVVM позволяют разбивать код на логические объекты, которые служат очень конкретным целям. Модели служат уровнем доступа к данным, где данные извлекаются и возвращаются в форматах, которые можно использовать во всем вашем приложении. Контроллеры обрабатывают запрос, обрабатывают данные, возвращаемые моделями, и загружают просмотры для отправки ответа. А представления — это шаблоны отображения (разметка, xml и т. д.), которые отправляются в ответ на запрос веб-браузеру.
MVC — наиболее распространенный архитектурный шаблон, используемый в популярных PHP frameworks.
Узнайте больше о MVC и его родственниках: