Contributed by
Ryan Weaver,
Fabien Potencier
in #15990.
microframework(微框架)在字面上指的是“简约的web程序框架”。开发者通常把这个词与“快速、小巧的框架”进行关联,例如Silex。但你也可以理解为简单、不强制的框架,你可以选择性地进入与架构有关的关键部分。
得益于弹性的内部架构,从第一天开始我们就可以把Symfony作为微框架来使用。不过,只有少数开发者以这种方式使用Symfony,因为它还不能完全保证便利性。
Symfony 2.8引入了一个全新的microkernel trait,来简化创建单文件(或仅仅更小)的Symfony程序。一个“Hello World”程序,若使用Symfony作为微框架的话,看上去像这样:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | // app/MicroKernel.php
use Symfony\Bundle\FrameworkBundle\Kernel\MicroKernelTrait;
use Symfony\Component\Config\Loader\LoaderInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Kernel;
use Symfony\Component\Routing\RouteCollectionBuilder;
class MicroKernel extends Kernel
{
use MicroKernelTrait;
public function registerBundles()
{
return array(new Symfony\Bundle\FrameworkBundle\FrameworkBundle());
}
protected function configureRoutes(RouteCollectionBuilder $routes)
{
$routes->add('/', 'kernel:indexAction', 'index');
}
protected function configureContainer(ContainerBuilder $c, LoaderInterface $loader)
{
$c->loadFromExtension('framework', ['secret' => '12345']);
}
public function indexAction()
{
return new Response('Hello World');
}
} |
单一的MicroKernel
类即可开启bundles并配置它们,定义路由,甚至控制controller代码。如果抛开强制使用的use
导入以及function
声明等关键字,上面例程中的实际PHP代码只有4行。反复地观想一下:一个全功能的Symfony程序只有四行代码!
这个新的microkernel,并未改善Symfony原始性能,因为它只是改变了路由和bundle的“注册方式”。不过,由于你只是开启了你要用到的功能,Symfony标准版的大量bundles都被禁用了。这就能够解释程序的性能在理解上的不同:
Symfony微框架的最强大之处在于,你正踩在Symfony的肩膀上构建你的程序,意味着你毋须面对寻常微框架所导致的各种束缚。所有不可思议的Symfony功能连同bundles,皆可在你的程序成长过程中“你所需要”的时候,立即投入使用。
下面的例程是,Hello World
程序被扩展为支持Twig模板、Web除错工具条以及Profiler分析器。这一切仍然可以单文件输出:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | // app/MicroKernel.php
class MicroKernel extends Kernel
{
use MicroKernelTrait;
public function registerBundles()
{
$bundles = array(
new Symfony\Bundle\FrameworkBundle\FrameworkBundle(),
new Symfony\Bundle\TwigBundle\TwigBundle(),
);
if (in_array($this->getEnvironment(), array('dev', 'test'), true)) {
$bundles[] = new Symfony\Bundle\WebProfilerBundle\WebProfilerBundle();
}
return $bundles;
}
protected function configureRoutes(RouteCollectionBuilder $routes)
{
$routes->mount('/_wdt', $routes->import('@WebProfilerBundle/Resources/config/routing/wdt.xml'));
$routes->mount('/_profiler', $routes->import('@WebProfilerBundle/Resources/config/routing/profiler.xml'));
$routes->add('/', 'kernel:indexAction', 'index');
}
protected function configureContainer(ContainerBuilder $c, LoaderInterface $loader)
{
// load bundles' configuration
$c->loadFromExtension('framework', [
'secret' => '12345',
'profiler' => null,
'templating' => ['engines' => ['twig']],
]);
$c->loadFromExtension('web_profiler', ['toolbar' => true]);
// add configuration parameters
$c->setParameter('mail_sender', 'user@example.com');
// register services
$c->register('app.markdown', 'AppBundle\\Service\\Parser\\Markdown');
}
public function indexAction()
{
return $this->container->get('templating')->renderResponse('index.html.twig');
}
} |
令程序“单文件化”绝非microkernel的本意。真实的使用场景是创建小型化的Symfony程序,也许它只在每个环境中使用了一个services.yml
文件和一个config.yml
文件,而路由在常规控制器类中以annotation方式被定义。以下是实现此需求时的完整代码示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | // app/MicroKernel.php
// ...
class MicroKernel extends Kernel
{
use MicroKernelTrait;
public function registerBundles()
{
return array(
new Sensio\Bundle\FrameworkExtraBundle\SensioFrameworkExtraBundle(),
new Symfony\Bundle\FrameworkBundle\FrameworkBundle(),
new Symfony\Bundle\TwigBundle\TwigBundle(),
new AppBundle\AppBundle(),
);
}
protected function configureRoutes(RouteCollectionBuilder $routes)
{
$routes->mount('/', $routes->import('@AppBundle/Controller', 'annotation'));
}
protected function configureContainer(ContainerBuilder $c, LoaderInterface $loader)
{
$loader->load(__DIR__.'/config/config_'.$this->getEnvironment().'.yml');
$loader->load(__DIR__.'/config/services.yml');
}
} |
在使用microkernel来替代AppKernel
时,一定不要忘记更新前端控制器:
1 2 3 4 5 6 7 8 9 10 | // web/app.php
use Symfony\Component\HttpFoundation\Request;
$loader = require __DIR__.'/../app/autoload.php';
require_once __DIR__.'/../app/MicroKernel.php';
$app = new MicroKernel('prod', false);
$app->loadClassCache();
$app->handle(Request::createFromGlobals())->send(); |
这样一来,如果你正在微框架和全功能框架之间进行选择的话,你将有一个全新的可能性。现在你可以在同一程序中同时拥有二者,并且毋须在功能上进行任何妥协。