ldl-framework/env-util

用于操作.env文件的实用工具

dev-main 2022-06-13 12:32 UTC

README

用于解析.env文件或直接.env字符串的实用工具,一些附加功能允许您添加转换或忽略某些行,您还可以扩展它以添加您自己的自定义转换。

主要的ENV文件概念

.env文件是一种用于指定不同代码环境(生产/预发布/开发)不同配置的文件。这些文件通常不会提交到git中,通常包含以下内容:

  • 注释
  • 变量(VAR=VALUE)
  • 空行

它们包含您的应用程序在每个环境中运行所必需的重要设置。

.env的一些有用用例示例

  • 在我的本地开发环境中创建一个新功能,该功能通过电子邮件通知用户,发送电子邮件必须被禁用。
  • 在我的本地开发环境中,我希望在每次请求中添加一些额外的调试信息。
  • 在我的本地开发环境中,数据库密码是123456
  • 在PRODUCTION环境中,数据库密码是
  • 在PRODUCTION环境中,不得在每次请求中添加调试信息。

LDL .env概念

env文件/字符串可以包含上述注释、变量、空行以及某些编译指令,这些指令允许我们对变量执行特殊操作/转换、跳过某些行或检测重复变量。

解析器和编译器

此包包含一系列解析器和编译器,在本节中我们将解释每个解析器的作用。

解析器

解析器的职责是解释/解析我们正在处理哪种类型的行,例如

它是一个注释吗?它是一个变量吗?它是一个空行吗?它是一个指令吗?它是一个无法解析的未知行吗?

对于每种不同的行类型,解析器将返回一个EnvLineCollection,其中包含代表每行的对象,回答我们之前的提问

它是一个注释吗?EnvLineComment它是一个变量吗?EnvLineVar它是一个空行吗?EnvEmptyLine它是一个指令吗?EnvCompilerDirective它是一个无法解析的未知行吗?EnvUnknownLine

解析代码示例(来自包含字符串的数组)

echo "Create Parser Collection\n";

$parserCollection = new EnvLineParserCollection([
    new EnvLineCommentParser(),
    new EnvLineCompilerDirectiveParser(),
    new EnvEmptyLineParser(),
    new EnvLineVarParser()
]);

$parser = new EnvParser();

//Lines to be parsed

$lines = [
    '#COMMENT LINE',
    'App_Admin_URL=https://:8080',
    'MAINTENANCE_MODE=0',
    'Hey whats up?',
    '!LDL-COMPILER START={"ignore": true}',
    'MUST_NOT_BE_SHOWN=1',
    'MUST_NOT_BE_SHOWN=2',
    '!LDL-COMPILER STOP'
];

echo "Lines to be parsed:\n";
echo var_export($lines,true)."\n\n";

echo "Parse lines:\n";
$lines = $parser->parse($lines);

foreach($lines as $line){
    dump(sprintf('%s = %s', get_class($line), $line));
}

上述代码的输出将是以下内容

Parse lines:
^ "LDL\Env\Util\Line\Type\Comment\EnvLineComment = #COMMENT LINE"
^ "LDL\Env\Util\Line\Type\Variable\EnvLineVar = App_Admin_URL=https://:8080"
^ "LDL\Env\Util\Line\Type\Variable\EnvLineVar = MAINTENANCE_MODE=0"
^ "LDL\Env\Util\Line\Type\EnvUnknownLine = UNKNOWN LINE"
^ "LDL\Env\Util\Line\Type\Directive\EnvLineDirective = !LDL-COMPILER START={"ignore": true}"
^ "LDL\Env\Util\Line\Type\Variable\EnvLineVar = MUST_NOT_BE_SHOWN=1"
^ "LDL\Env\Util\Line\Type\Variable\EnvLineVar = MUST_NOT_BE_SHOWN=2"
^ "LDL\Env\Util\Line\Type\Directive\EnvCompilerDirective = !LDL-COMPILER STOP"

所有不同的核心解析器都可以在以下文件夹中找到

src/Env/Util/Line/Parser/*

对于完整的示例,请参阅

EnvStringParsingExample

EnvFileParser

在大多数情况下,您将需要解析文件,为此,有一个EnvFileParser类,它具有一个解析方法,该方法接受一组可迭代的项,您可以传递一个数组或实现\Traversable的对象,内部此集合将转换为ReadableFileCollection,如果文件不可读,将抛出异常。

示例

$parser = new EnvFileParser();

$parser->parse([
    '/path/to/file1/.env',
    '/path/to/file2/.env'
]);

foreach($lines as $line){
    dump(sprintf('%s = %s', get_class($line), $line));
}

对于完整的示例,请参阅

EnvFileParsingExample

编译器

编译器的主要功能可以被视为“获取一系列行并对其应用一些转换”

EnvCompiler类有一个compile方法,它接受一个EnvLineCollection,理想情况下,这个集合将是之前解析的字符串/文件的返回值。

//See parser example above
$parsedLines = $parser->parse();

$compiler = new EnvCompiler();
$compiled = $compiler->compiler($parsedLines);

foreach($compiled as $line){
   echo "$line\n";
}

输出

#COMMENT LINE
App_Admin_URL=https://:8080
MAINTENANCE_MODE=0"

EnvCompiler类使用一个EnvCompilerDirectiveCollection,这个集合中的每个项目都必须是EnvCompilerDirectiveInterface的一个实例。这个集合可以作为构造函数参数传递给EnvCompiler(这样您就可以添加一组自定义的编译指令),或者创建一个包含核心编译器的默认集合。

指令

编译指令允许您对变量应用转换,当找到重复的变量名时抛出异常,跳过空行等。

创建指令

创建指令有多种方式,最简单和最直接的方法是从字符串创建它,然后解析该字符串指令以获取对象。

从字符串创建指令

<?php declare(strict_types=1);

use LDL\Env\Util\Line\Parser\Directive\EnvLineCompilerDirectiveParser;

$myDirective = '!LDL-COMPILER START={"VAR_NAME_CASE":null,"IGNORE":false,"COMMENTS":false,"ONDUPLICATEVAR":"throw","ONUNKNOWLINE":"discard"}';
$parser = new EnvLineCompilerDirectiveParser();

//Create the directive from string
$directive = $parser->createFromString($myDirective);

从自定义指令创建EnvLineDirective

您还可以从对象创建指令

<?php declare(strict_types=1);

use LDL\Env\Util\Compiler\Collection\EnvCompilerDirectiveCollection;
use LDL\Env\Util\Compiler\Directive\EnvVarCaseTransformCompilerDirective;
use LDL\Env\Util\Line\Type\Directive\Factory\EnvLineDirectiveFactory;
use LDL\Env\Util\Compiler\Directive\EnvSkipEmptyCompilerDirective;

$directives = new EnvCompilerDirectiveCollection([
    new EnvVarCaseTransformCompilerDirective(
        EnvVarCaseTransformCompilerDirective::CASE_UPPER
    ),
    new EnvSkipEmptyCompilerDirective()
]);

$directive = EnvLineDirectiveFactory::createStart($directives);

echo $directive->getString();

上一段代码的输出将是

!LDL-COMPILER START={"VAR_NAME_CASE":"UPPER","SKIP_EMPTY":true}

从指令对象获取指令

最后一种情况是从EnvLineDirectiveInterface对象获取可用指令作为对象

<?php declare(strict_types=1);

use LDL\Env\Util\Line\Parser\Directive\EnvLineCompilerDirectiveParser;
use LDL\Env\Util\Line\Type\Directive\Factory\EnvLineDirectiveFactory;

$myDirective = '!LDL-COMPILER START={"COMMENTS":false,"ONDUPLICATEVAR":"throw","ONUNKNOWLINE":"discard"}';
$parser = new EnvLineCompilerDirectiveParser();

//Create the directive from string
$directive = $parser->createFromString($myDirective);

$directives = EnvLineDirectiveFactory::getDirectives($directive);

foreach($directives as $directive){
    dump(get_class($directive));
    dump($directive->toArray());
}

$directive = EnvLineDirectiveFactory::createStart($directives);

echo $directive->getString();

输出

^ "LDL\Env\Util\Compiler\Directive\EnvIgnoreCommentsCompilerDirective"
^ array:1 [
  "COMMENTS" => false
]
^ "LDL\Env\Util\Compiler\Directive\EnvDuplicateVarResolverCompilerDirective"
^ array:1 [
  "ONDUPLICATEVAR" => "throw"
]
^ "LDL\Env\Util\Compiler\Directive\EnvUnknownLineCompilerDirective"
^ array:1 [
  "ONUNKNOWLINE" => "discard"
]

!LDL-COMPILER START={"COMMENTS":false,"ONDUPLICATEVAR":"throw","ONUNKNOWLINE":"discard"}

默认核心编译指令

  • EnvSkipEmptyCompilerDirective

跳过空行

  • EnvVarCaseTransformCompilerDirective

转换变量的大小写(大写或小写),

  • EnvIgnoreLineCompilerDirective

使用此指令时,下面的行将被忽略,

  • EnvIgnoreCommentsCompilerDirective

忽略所有注释

  • EnvDuplicateVarResolverCompilerDirective

如果找到一个具有重复名称的变量,可以抛出异常,或者指定使用哪个变量的解决方案。

  • EnvUnknownLineCompilerDirective

默认情况下,如果找到未知行,将抛出异常,也可以丢弃该行。

默认核心编译指令可以在以下位置找到

src/Env/Util/Compiler/Directive

EnvCompiler编译方法

编译方法的工作方式如下

  • 当找到一个起始EnvLineDirective时,该指令将应用于剩余的行
  • 如果找到另一个起始指令,该指令将接管,之前的指令将丢失
  • 当找到一个停止EnvLineDirective时,不会应用任何指令。

注意:如果您通过构造函数在EnvCompiler中设置了一个主指令,当找到停止指令时,将使用主指令。

待办事项

  • 编写如何创建自己的解析器的说明
  • 编写如何创建自己的编译指令的说明