【问题标题】:PSR-1: 2.3. Side Effects: variable inside config filePSR-1:2.3。副作用:配置文件中的变量
【发布时间】:2020-03-25 17:51:34
【问题描述】:

PSR-1 包含推荐2.3. Side Effects

一个文件应该声明新的符号(类、函数、常量等)并且不会引起其他副作用,或者它应该执行具有副作用的逻辑,但不应该两者都做。

在 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 还是很陌生。

我是否错过了任何巧妙的方法来摆脱变量,同时保持可读性?

推论是:坚持严格遵守建议的严肃项目如何处理这个问题?

【问题讨论】:

  • 我不会在定义中使用任何函数。你不能保证结果总是一样的。在这种情况下,我将使用具有硬编码值的不同配置文件,例如 live.conf.php 和 dev.conf.php。根据您包含一个或另一个文件的环境。
  • 但是我会将凭据提交给 git,这绝不是一个好主意。在本地使用 .env 和在 prod 中使用 Heroku,不想停止使用它们。
  • 这个概念是拥有完全不同的配置。您可以 .gitignore 它们,只需将 example.conf.php 放入存储库。
  • 你在使用任何依赖注入容器(DI容器)吗? / 项目中常量的最佳使用:常量应该在 .env 文件中找到,或者作为类常量。所以没有define()。 / 你真的需要解析一个 db url 吗?建议:定义需要的.env常量(DB_DSNDB_USERDB_PASSWORD等),在需要的地方直接使用。
  • @dakis 感谢有关避免define()s 的提示。尚未使用任何依赖注入。在 prod 中,我在 Heroku 上,将应用程序链接到其数据库的标准方法是通过 DATABASE_URL=postgres://u123:pabc@ec2.eu-west-1.compute.amazonaws.com:5432/dxyz 设置(超级类似于 .env),所以我宁愿在 dev 中使用类似的方法。我想我可以将解析移到另一个文件,然后putenv()

标签: php standards psr-1 php-fig


【解决方案1】:

1。没关系,别出汗了

您已在问题中提到它,但此建议是应该而不是必须。 如果这是您整个项目中唯一的 PSR-1 问题:干得好!

但你的问题是:其他项目是如何进行的?

2。远离配置的定义

如果使用不当,全局常量是依赖磁铁。它们引入了耦合,使您的代码更难消化。 This Q&A is a very good read on why you should move away from them.

改用依赖注入(是的,标量配置常量也是依赖)。

3。案例研究:Symfony

基于Symfony的项目使用:

  • YAML(推荐)或 XML 配置文件到 configure 依赖注入容器,以及
  • environment variables,设置特定于应用程序运行的每个环境的配置选项。这些 env vars 在特定于环境的 .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 环境变量注入到需要它的类中。

然后您将在My\Database\Factory 类的构造函数中解析DATABASE_URL,并使用结果来构造您的数据库类。

优点:

  • 配置与代码分离
  • 配置易于更改
  • 配置易于阅读

缺点:

  • 依赖注入和使用 DI 容器有一个学习曲线,需要改变构建对象的方式。

【讨论】:

【解决方案2】:

twelve-factors app 方法中所述:

应用有时会将配置存储为代码中的常量。这违反了十二因素,要求严格分离配置与代码。配置因部署而异,但代码没有。

十二因素应用程序将配置存储在环境变量中。环境变量很容易在部署之间更改而无需更改任何代码

您在最佳实践方面处于正确的轨道上,您只需要纠正一些错误。

1。为环境变量使用变量

您想将常量用于非常量。数据库名称的值可能因环境而异。它不是一个常量,它是一个(环境)变量,您应该使用$dbName = getenv('DB_NAME')
相比之下,数字 π 是一个常数,它永远不会改变,可以硬编码。

您可以查看 Composer 或 Symfony 组件等开源项目的源代码,您会看到 getenv() 仅用于填充变量。

2。直接使用配置中预期的元素

在您的情况下,您不应将完整的数据库 URL 用作单个配置项。您应该按照配置的预期将环境变量中的每个元素分开,例如 DB_HOSTDB_NAMEDB_PORT

【讨论】:

  • 谢谢。我同意第 1 点,但 #2 的论点是什么?十二要素应用程序由 Heroku 的联合创始人 Adam Wiggins 编写。我使用的单行数据库配置直接来自 Heroku:DATABASE_URL=postgres://u123:pabc@ec2.eu-west-1.compute.amazonaws.com:5432/dxyz;可以将其全部放在一行中(使编辑/重用/复制更容易;当您需要更改其中一个值时,您通常也需要更改其他值。)
  • 如果您真的想使用define(),您将不再面临您的问题。在您的情况下,配置需要分离的元素。直接添加预期参数比不需要额外和不必要的处理来解析元素(这是您的问题的原因)的预期参数更简单。对于需要 DATABASE_URL 参数的配置,例如 Heroku 或 Symfony,那么我们只需要这个唯一的参数。
猜你喜欢
  • 2012-10-29
  • 2014-11-21
  • 2019-01-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-06-15
  • 1970-01-01
相关资源
最近更新 更多