如何读取?如何保存?这是重点php
逐行正则匹配,一次不能多行。且只能定义
bool
/string
类型。laravel
getenv
: laravel的env是经过该函数获取env环境变量 那么存储呢?使用了Dotenv包 加载以下:Dotenv\Loader类下:数据库
/** * Load `.env` file in given directory. * * @return array */ public function load() { $this->ensureFileIsReadable(); $filePath = $this->filePath; $lines = $this->readLinesFromFile($filePath); foreach ($lines as $line) { if (!$this->isComment($line) && $this->looksLikeSetter($line)) { $this->setEnvironmentVariable($line); } } return $lines; }
说明加载env文件效率比较低。apache
顺着getEnvironmentVariable
往下:bootstrap
public function setEnvironmentVariable($name, $value = null) { // 这里就是解析了 list($name, $value) = $this->normaliseEnvironmentVariable($name, $value); // Don't overwrite existing environment variables if we're immutable // Ruby's dotenv does this with `ENV[key] ||= value`. if ($this->immutable && $this->getEnvironmentVariable($name) !== null) { return; } // If PHP is running as an Apache module and an existing // Apache environment variable exists, overwrite it if (function_exists('apache_getenv') && function_exists('apache_setenv') && apache_getenv($name)) { apache_setenv($name, $value); } if (function_exists('putenv')) { putenv("$name=$value"); } $_ENV[$name] = $value; $_SERVER[$name] = $value; }
上面的代码会注意到:apache_getenv
和apache_setenv
和putenv
对于apche_getenv
: http://php.net/manual/zh/function.apache-setenv.php缓存
putenv
: 添加 setting 到服务器环境变量。 环境变量仅存活于当前请求期间。 在请求结束时环境会恢复到初始状态。服务器
优势:一、优雅 二、稳定性 先看他的优雅写法:app
list($name, $value) = array_map('trim', explode('=', $name, 2));
对于稳定性: 上面设置了$_ENV
、$_SERVER
、putenv
这些都是为了跨平台的稳定性,若是其中一个变量不可用,就从另外一个中获取。ide
解析过程函数
/** *规范化给定的环境变量。 * *取得开发人员传入的值和: * - 确保咱们处理单独的名称和值,若是须要,将名称字符串分开,引号 * - 解析变量值, * - 解析带有双引号的变量名, * - 解析嵌套变量。 * * @param string $ name * @param string $ value * * @return array */ protected function normaliseEnvironmentVariable($name, $value) { // 就是简单的 array_map('trim', explode('=', $name, 2)); 根据等号分开而且去除两边空格 list($name, $value) = $this->splitCompoundStringIntoParts($name, $value); // 解析净化变量名 list($name, $value) = $this->sanitiseVariableName($name, $value); // 解析净化变量值 这个是最复杂的部分 list($name, $value) = $this->sanitiseVariableValue($name, $value); $value = $this->resolveNestedVariables($value); return array($name, $value); } protected function sanitiseVariableName($name, $value) { // 支持 export方式定义变量,把单引号和双引号去掉 $name = trim(str_replace(array('export ', '\'', '"'), '', $name)); return array($name, $value); } // protected function sanitiseVariableValue($name, $value) { $value = trim($value); if (!$value) { return array($name, $value); } if ($this->beginsWithAQuote($value)) { // value starts with a quote $quote = $value[0]; // 支持引号的方式定义环境变量 $regexPattern = sprintf( '/^ %1$s # match a quote at the start of the value ( # capturing sub-pattern used (?: # we do not need to capture this [^%1$s\\\\] # any character other than a quote or backslash |\\\\\\\\ # or two backslashes together |\\\\%1$s # or an escaped quote e.g \" )* # as many characters that match the previous rules ) # end of the capturing sub-pattern %1$s # and the closing quote .*$ # and discard any string after the closing quote /mx', $quote ); $value = preg_replace($regexPattern, '$1', $value); $value = str_replace("\\$quote", $quote, $value); $value = str_replace('\\\\', '\\', $value); } else { // 没有引号 每一行的均可能有#注释须要去掉 $parts = explode(' #', $value, 2); #相似这样得注释 $value = trim($parts[0]); // 区井号#前面的部分做为值。这里就须要注意了 // Unquoted values cannot contain whitespace 非引号包含的值,不能包含空格 if (preg_match('/\s+/', $value) > 0) { throw new InvalidFileException('Dotenv values containing spaces must be surrounded by quotes.'); } } return array($name, trim($value)); } // 是否包含单引号或者双引号 protected function beginsWithAQuote($value) { return strpbrk($value[0], '"\'') !== false; }
使用php artisan config:cache
以后env
函数再也不有用,就是从getenv
没法获取数据?缘由?
由于cache
了以后,laravel
就会将全部config
生成缓存文件,而且判断若是缓存文件生成,就不会加载.env
文件,所以env函数就不会获取导数据啦,那么是哪里判断了? \Illuminate\Foundation\Bootstrap\LoadEnvironmentVariables
类在做怪!!
public function bootstrap(Application $app) { // 是否缓存config目录的配置了,缓存了就不会去加载.env if ($app->configurationIsCached()) { return; } // 检查env应该加载哪个文件 $this->checkForSpecificEnvironmentFile($app); try { // 这个时候才加载 .env (new Dotenv($app->environmentPath(), $app->environmentFile()))->load(); } catch (InvalidPathException $e) { // } }
这个加载环境变量是何时加载的? 看Kernel
内核代码,laravel
的内核分为console
和http
两种。咱们固然看http
的。 \Illuminate\Foundation\Http\Kernel
类
protected $bootstrappers = [ \Illuminate\Foundation\Bootstrap\LoadEnvironmentVariables::class, \Illuminate\Foundation\Bootstrap\LoadConfiguration::class, \Illuminate\Foundation\Bootstrap\HandleExceptions::class, \Illuminate\Foundation\Bootstrap\RegisterFacades::class, \Illuminate\Foundation\Bootstrap\RegisterProviders::class, \Illuminate\Foundation\Bootstrap\BootProviders::class, ];
能够看到,加载env变量是启动的第一步,而后就是加载config目录的文件。这些类都有一个叫bootstrap的方法。
一、.env
文件的变量有注释功能 二、保存在请求期间的环境变量中 三、重点:在config:cache
以后不会加载env
,所以不能再config
目录之外的文件使用env
函数,不然将会致使程序以超乎想象的方式运行。我相信你的程序多少会出现这个问题。 四、非引号包含的值,不能包含空格 五、值会去除井号#
后面部分保留前面部分,这就可能有问题了。好比:
# 数据库密码包含井号,那咋办? # 错误 db_password=12345#%snq # 正确 使用引号 db_password="12345#%snq"
下一节就是阅读LoadConfiguration
源码了-config目录的加载。