ПСР-1: 2.3. Побочные эффекты: переменная внутри конфигурационного файла
PSR-1 включает рекомендацию 2.3. Побочные эффекты:
В файле СЛЕДУЕТ объявлять новые символы (классы, функции, константы и т. Д.) И не вызывать других побочных эффектов, либо он ДОЛЖЕН выполнять логику с побочными эффектами, но НЕ ДОЛЖЕН делать и то, и другое.
Рассмотрим этот пример (мой собственный) внутри файла config.php:
/**
* Parsing the database URL.
* DATABASE_URL is in the form:
* postgres://user:password@hostname:port/database
* e.g.:
* postgres://u123:pabc@ec2.eu-west-1.compute.amazonaws.com:5432/dxyz
*/
$url = parse_url(getenv('DATABASE_URL'));
define('DB_HOST', $url['host']);
define('DB_NAME', substr($url['path'], 1)); // get rid of initial slash
define('DB_USER', $url['user']);
define('DB_PASSWORD', $url['pass']);
Если я сделаю это, я фактически не соблюдаю рекомендацию. phpcs по праву будет жаловаться на это из-за переменной:
FILE: config.php
-----------------------------------------------------------------------------------------------------------------
FOUND 0 ERRORS AND 1 WARNING AFFECTING 1 LINE
-----------------------------------------------------------------------------------------------------------------
1 | WARNING | A file should declare new symbols (classes, functions, constants, etc.) and cause no other side
| | effects, or it should execute logic with side effects, but should not do both. The first symbol
| | is defined on line 17 and the first side effect is on line 162.
-----------------------------------------------------------------------------------------------------------------
Альтернативой может быть следующее:
define('DB_HOST', parse_url(getenv('DATABASE_URL'))['host']);
define('DB_NAME', substr(parse_url(getenv('DATABASE_URL'))['path'], 1));
define('DB_USER', parse_url(getenv('DATABASE_URL'))['user']);
define('DB_PASSWORD', parse_url(getenv('DATABASE_URL'))['pass']);
Нет переменной - нет проблем. Но это ВЛАЖНО и трудно читать.
Я понимаю, что рекомендация такова, и в ней написано "ДОЛЖЕН", а не "ДОЛЖЕН". Но это все еще меня беспокоит… Во-первых, каждый раз, когда я проверяю файл, phpcs будет жаловаться на это, но сообщать об этом только один раз в строке, оставляя дверь открытой для добавления дополнительных "побочных эффектов", которым нет места в файле конфигурации.
Я все еще новичок в этой теме PSR.
Пропустил ли я какой-нибудь умный способ избавиться от переменной, сохранив при этом читабельность?
Следствием может быть: как с этим справляются серьезные проекты, которые настаивают на точном выполнении рекомендаций?
2 ответа
1. Все в порядке, не переживайте
Вы уже упоминали об этом в своем вопросе, но эту рекомендацию СЛЕДУЕТ, а не ОБЯЗАТЕЛЬНО. Если это единственная проблема PSR-1 во всем вашем проекте: молодец!
Но ваш вопрос был таков: как это делают другие проекты?
2. Отойдите от определений для настройки
Глобальные константы при неправильном использовании являются магнитами зависимости. Они вводят связь и усложняют усвоение кода. Эти вопросы и ответы - очень хорошее прочтение того, почему вам следует от них отойти.
Вместо этого используйте внедрение зависимостей (да, константы скалярной конфигурации также являются зависимостями).
3. Пример использования: Symfony
В проектах на базе Symfony используются:
- файлы конфигурации YAML (рекомендуется) или XML для настройки контейнера внедрения зависимостей вместе с
- переменные среды, чтобы установить параметры конфигурации, специфичные для каждой среды, в которой должно работать приложение. Эти переменные env определены в файлах .env для конкретной среды.
Например, чтобы настроить службу базы данных в проекте Symfony, вы должны создать файл YAML, содержащий:
services:
My\Database\Factory: # <-- the class we are configuring
arguments:
$url: '%env(DATABASE_URL)' # <-- configure the $url constructor argument
Symfony компилирует это в код PHP, вставляя DATABASE_URL
переменную среды в класс, который этого требует.
Затем вы проанализируете DATABASE_URL
в конструкторе My\Database\Factory
class и используйте результат для создания класса базы данных.
Плюсы:
- Конфигурация отделена от кода
- Конфигурацию легко изменить
- Конфигурация легко читается
Минусы:
- Внедрение зависимостей и использование контейнера DI требует обучения и изменения вашего подхода к построению объектов.
Как указано в методологии приложения с двенадцатью факторами:
Иногда приложения хранят конфигурацию в виде констант в коде. Это нарушение двенадцати факторов, которое требует строгого отделения конфигурации от кода. Конфигурация существенно различается в зависимости от развертывания, код - нет.
Приложение с двенадцатью факторами хранит конфигурацию в переменных среды. Вары env легко менять между развертываниями без изменения кода
Вы на правильном пути в отношении лучших практик, вам просто нужно исправить некоторые ошибки.
1. Используйте переменные для переменных среды
Вы хотите использовать константы для вещей, которых нет. Значение имени базы данных может варьироваться в зависимости от среды. Это НЕ константа, это переменная (среды), вы должны использовать$dbName = getenv('DB_NAME')
.
Напротив, число π является постоянным, оно никогда не изменится и его можно жестко запрограммировать.
Вы можете взглянуть на исходный код проектов с открытым исходным кодом, таких как Composer или компоненты Symfony, вы увидите getenv()
используется только для заполнения переменных.
2. Используйте непосредственно элементы, ожидаемые в конфигурации.
В вашем случае вы не должны использовать полный URL-адрес базы данных в качестве единственного элемента конфигурации. Вместо этого вы должны разделить каждый элемент в переменных среды, напримерDB_HOST
, DB_NAME
, DB_PORT
, как и ожидалось конфигурацией.