ldl-framework / env-util
用于操作.env文件的实用工具
Requires
- php: >=7.3
- ext-json: *
- ldl-framework/file-common: dev-master
- ldl-framework/framework-base: dev-master
- ldl-framework/typed-collection: dev-master
- symfony/string: ^5.1
This package is auto-updated.
Last update: 2024-09-13 17:46:59 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/*
对于完整的示例,请参阅
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)); }
对于完整的示例,请参阅
编译器
编译器的主要功能可以被视为“获取一系列行并对其应用一些转换”
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中设置了一个主指令,当找到停止指令时,将使用主指令。
待办事项
- 编写如何创建自己的解析器的说明
- 编写如何创建自己的编译指令的说明