如何掌握创建新的环境
每一个应用程序都是由代码和一组“规定了代码如何执行”的配置信息组合而成。配置能够定义使用的数据库,或者是否应该缓存一些内容,又或冗长的日志应该如何处理。
在Symfony中,“环境”的思想就是令相同的代码库可以运行在不同的配置之下。例如,dev
环境应当使用可令开发简单、友好的配置信息,然而prod
环境就应当使用一组优化了速度的配置。
不同的环境,不同的配置文件 ¶
典型的Symfony程序始于三个环境:dev
,
prod
, 和test
。就像之前提到的,每种环境都是一种“以不同配置信息执行相同代码库”的呈现方式。因此每种环境要加载它自己的配置文件并不奇怪。如果你使用YAML配置格式,下面的文件将(在加载时)被使用:
- 对于
dev
环境:app/config/config_dev.yml
- 对于
prod
环境:app/config/config_prod.yml
- 对于
test
环境:app/config/config_test.yml
这种加载是通过AppKernel
类中默认要用到的一个简单标准所实现的:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
// app/AppKernel.php
// ...
class AppKernel extends Kernel
{
// ...
public function registerContainerConfiguration(LoaderInterface $loader)
{
$loader->load($this->getRootDir().'/config/config_'.$this->getEnvironment().'.yml');
}
} |
你可以看到,当Symofny被加载时,它使用了给定的环境来决定“加载哪种配置”。这就漂亮地解决了“多环境”的问题,以一种强大而透明的方式。
当然,现实中,每种环境都只是部分不同于其他。基本上,所有环境都将共享大面积的常规配置。打开config_dev.yml
配置文件,你可以看到这是多么轻松而透明地被实现:
1 2 3 4 |
imports:
- { resource: config.yml }
# ... |
1 2 3 4 5 |
<imports>
<import resource="config.xml" />
</imports>
<!-- ... --> |
1 2 3 |
$loader->import('config.php');
// ... |
要共享配置信息,每种环境的配置文件首先要导入一个中央配置文件(central configuration file,config.yml
)。(原有)文件的其余部分,可以通过覆写个别参数来脱离(中央)默认配置。例如,默认时web_profiler
是关闭的。然而在dev
环境中,通过修改toolbar
选项的值,可以在config_dev.yml
配置文件中激活工具条:
1 2 3 4 5 6 7 |
# app/config/config_dev.yml
imports:
- { resource: config.yml }
web_profiler:
toolbar: true
# ... |
1 2 3 4 5 6 |
<!-- app/config/config_dev.xml -->
<imports>
<import resource="config.xml" />
</imports>
<webprofiler:config toolbar="true" /> |
1 2 3 4 5 6 7 8 |
// app/config/config_dev.php
$loader->import('config.php');
$container->loadFromExtension('web_profiler', array(
'toolbar' => true,
// ...
)); |
在不同的环境下执行程序 ¶
要在每个环境中执行程序,使用app.php
(对于 prod
环境) 或者 app_dev.php
(对于 dev
环境) 的前端控制器:
1 2 |
Http://localhost/app.php -> *prod* environment
http://localhost/app_dev.php -> *dev* environment |
如果你的URL中的文件名中没有两者中的一个,那么将由web服务器来决定哪个 文件在背后被执行。如果你用了PHP内建的web server,它知道要去执行app_dev.php
文件。在生产环境下,配置你的web服务器来使用app.php
这个文件。另外,两者中必有其一被执行(译注:一个环境执行时,另一个将停止)。
上面给定的URL,假设你的web服务器被配置为使用web/
目录作为程序的根目录,参考安装Symofny以了解更多。
如果你打开这些(前端控制器)文件,你会立即看到被它们所使用的环境都被显式地设置了:
1 2 3 4 5 6 |
// web/app.php
// ...
$kernel = new AppKernel('prod', false);
// ... |
prod
这个值指定了程序将要运行在prod
环境下。一个Symfony的程序,可以靠着使用这行代码并改变“环境字符串”来执行任何一种环境。
test
环境,在编写功能测试时要用到,它不能通过控制器在浏览器里直接访问。换句话说,不像其他环境,并没有一个app_test.php
前端控制器文件。
为命令行选择环境 ¶
默认时,Symfony的命令行在dev
环境下执行,同时开启debug mode。使用--env
和 --no-debug
选项来调整这种行为:
1 2 3 4 5 6 7 8 |
# 'dev' environment and debug enabled
$ php bin/console command_name
# 'prod' environment (debug is always disabled for 'prod')
$ php bin/console command_name --env=prod
# 'test' environment and debug disabled
$ php bin/console command_name --env=test --no-debug |
除了--env
和 --debug
选项之外,Symfony命令行的行为也被环境变量(environment variables)所控制。在执行命令之前,Symfony控制台程序要检查环境变量是否存在以及它们的值:
SYMFONY_ENV
- 把命令的“执行环境”设置为这个变量(译注:指的是--env)的值(
dev
,prod
,test
等等); SYMFONY_DEBUG
- 如果是
0
,debug mode关闭。否则debug mode将被开启。
对于生产环境下的服务器来说这个环境变量特别有用,因为它们能够让你确保那条命令始终运行在prod
环境下而毋须添加任何辅助的命令选项。
创建一个新环境 ¶
Symfony程序的三个默认环境可以满足多数使用场景。当然,由于一个环境就是一个字符串,对应于一组配置信息,那么创建一个全新环境也就相当容易了。
假设,例如在部署之前,你需要对程序进行检测(benchmark)。一种方式就是使用接近生产环境的配置,但却开启Symfony的web_profiler
。这可以让Symfony记录下你的程序在接受检查过程中的相关信息。
完成这个的最佳方式,则是通过一个全新环境,比如称其为benchmark
。先创建一个新的配置文件:
1 2 3 4 5 6 |
# app/config/config_benchmark.yml
imports:
- { resource: config_prod.yml }
framework:
profiler: { only_exceptions: false } |
1 2 3 4 5 6 7 8 |
<!-- app/config/config_benchmark.xml -->
<imports>
<import resource="config_prod.xml" />
</imports>
<framework:config>
<framework:profiler only-exceptions="false" />
</framework:config> |
1 2 3 4 5 6 |
// app/config/config_benchmark.php
$loader->import('config_prod.php')
$container->loadFromExtension('framework', array(
'profiler' => array('only-exceptions' => false),
)); |
由于(容器)参数被解析的方式,你不能使用它们来动态构建“被导入的路径”。这意味着下面这种配置将无法工作:
1 2 3 |
# app/config/config.yml
imports:
- { resource: "%kernel.root_dir%/parameters.yml" } |
1 2 3 4 5 6 7 8 9 10 11 |
<!-- app/config/config.xml -->
<?xml version="1.0" encoding="UTF-8" ?>
<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/dic/services
http://symfony.com/schema/dic/services/services-1.0.xsd">
<imports>
<import resource="%kernel.root_dir%/parameters.yml" />
</imports>
</container> |
1 2 |
// app/config/config.php
$loader->import('%kernel.root_dir%/parameters.yml'); |
由于有了这个简单的扩展,程序现在可以支持一个全新环境即benchmark
了。
这个新配置文件从prod
环境中导入配置,然后更改(覆写)了它。这可以确保全新环境不同于prod
环境,除了文件中那些被显式修改了的地方之外。
因为你希望这个环境可以通过浏览器来访问,你应该为它创建一个前端控制器。拷贝web/app.php
文件到web/app_benchmark.php
,然后把“环境”编辑为benchmark
:
1 2 3 4 5 6 7 |
// web/app_benchmark.php
// ...
// change just this line
$kernel = new AppKernel('benchmark', false);
// ... |
1 |
http://localhost/app_benchmark.php |
新环境已经可以访问到,通过:
一些环境,像是dev
,永远不可以在“已部署的服务器”上被公开访问到。这是因为特定的环境皆有调试(debugging)之目的,会给出“程序/程序背后的基础设施”的大量信息。为了确保这些环境不被访问到,前端控制器一般通过下面这种“基于控制器”的代码来防范外部IP地址:
1 2 3 |
if (!in_array(@$_SERVER['REMOTE_ADDR'], array('127.0.0.1', '::1'))) {
die('You are not allowed to Access this file. Check '.basename(__FILE__).' for more information.');
} |
环境和缓存目录 ¶
Symfony在很多方面都利用到缓存:程序配置、路由配置、Twig模板以及其他许多内容,都是被缓存为PHP对象并以文件方式存于文件系统中。
默认时,这些缓存文件大量被存入var/cache
目录下。然而,每种环境都在对自己的文件进行缓存:
1 2 3 4 5 6 |
your-project/
├─ var/
│ ├─ cache/
│ │ ├─ dev/ # cache directory for the *dev* environment
│ │ └─ prod/ # cache directory for the *prod* environment
│ ├─ ... |
有时,在debugging的时候“通过检查缓存文件来了解某些东西是如何运作的”是有用的。这样做的时候,记得在当前所使用的环境之目录下进行寻找(开发和调试中,多数时候都是dev
)。但也可能不同,var/cache/dev
目录包括以下内容:
appDevDebugProjectContainer.php
- 缓存版的“服务容器”,里面有缓存的程序级配置。
appDevUrlGenerator.php
- 从路由配置信息中生成的PHP类,用于生成URL。
appDevUrlMatcher.php
- 用于匹配路由的PHP类——在这里可以找到被编译过的正则表达式,用于匹配传入的URLs(并映射)到不同的路由。
twig/
- 这个目录包含了所有的缓存了的Twig模板。
你可以很容易地改变目录位置及其名称。更多内容请参考如何覆写Symfony默认的目录结构一文。
Going Further ¶
参考如何在服务容器中设置外部参数