ПСР-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, как и ожидалось конфигурацией.

Другие вопросы по тегам