Symfoy2 是什么?
PHP世界里又一廣受關注的web MVC框架? Fabien Potencier 卻不這么說!
Fabien Potencier這樣定義Symfoy2 是個什么東西:
首先,Symfony2 是一個獨立,松散的,有組織嚴密的PHP組件集合,它可以為你解決一些web開發中遇到的一般性問題。
其次,基於這些組件,Symfoy2 也可以作為一個獨立的web框架使用。
那么Symfony2 是一個MVC框架嗎?
Fabien Potencier 說Symfony2從來沒有把自己定義為一個MVC框架!
那它是什么? Fabien Potencier 我們從來不關心MVC模式,關心的只有各個關注點的分離(separation of concerns)。
但是Symfony2 還是提供了部分的MVC模式的實現:比如Controller部分,View部分卻沒有Mode部分不過你可以通過和它緊密繼承的ORM(Doctrine2和Propel)實現。
從這個角度看Symfony的確也沒有逃出web MVC框架的圈子啊!!!
Fabien Potencier 又說Symfony2從來就沒有想靠這些ORM來使自己成為另一個MVC的追隨者,我們的目標更遠大!
告訴你吧, Symfony2 是一個HTTP框架或者說是一個Request/Response 框架。我們緊盯的目標不是MVC模式,而是HTTP協議,我們是更低級的更基礎的框架。
我們為什么要這么說呢? 有根據的!
近幾年隨着web的發展,有時候你只需要創建一組REST API,所有的邏輯都放到瀏覽器端,服務器端只提供數據就是一種web了。不信你看 backbone.js !
再說了,MVC模式只不過是Web 應用程序的其中一種實現方式罷了。
剝去所有框架模式的皮,你看看那個web程序不是處理一個接收到的Request然后返回一個Response啊?
我們Symfony2 抓住的就是web程序的根本! 再說我們眾多的HTTP流媒體有哪個會選擇使用MVC呢?
總之,我們Symfony2比MVC更靠近根本,我們更底層,更通用!!!
說起Symfony2,Fabien Potencier說我們有着更加遠大的目標,怎么解釋呢?
Symfony2 將繼續專注於Pack技術的研究和創新!我們相信她會繼續推動web的向前發展。
先看看Symfony2 中我們已經包含的創新吧!
從Bundles,HTTP 緩存,分布式,依賴注入,模板引擎,聲明式配置,資產管理,穩定的API到web分析器等等一系列技術都對web的發展起到了巨大的推動作用。
“ 要知道一個獨立的框架永遠不可能成為PHP世界里的一個標准,所以Symfony2 在探尋另外一條路!”
“ 共享無處不在。”
“ 我們不能重復制造輪子。”
因此,我們緊密的集成了Monolog,Composer,Doctrine,Propel,Assetic,Twig,Swiftmailer等偉大產品。
更重要的是我們想跟大家分享我們的工作!
所以,我們最終選擇了走組件(components)化這條路!
我們將為一切web項目提供建築模塊,無論是個人項目還是商業項目,更或者是開源項目!
據說在Symfony2 的代碼中可能會有標志為@api的類或者方法,它意味着一個方法從名字到參數以及返回值都不會因為Symfony2發展版本而變化,所以,如果
你的項目只使用了這些,那么你就不用擔心Symfony2的版本升級問題。
看看Symfony2 現在擁有的組件吧:
DependencyInjection
EventDispatcher
HttpFoundation
DomCrawler
ClassLoader
CssSelector
HttpKernel
BrowserKit
Templating
Translation
Serializer
Validator
Security
Routing
Console
Process
Config
Finder
Locale
Yaml
Form
Fabien 簡單介紹了幾個bundle:
1. ClassLoader:
實現了PSR-o 標准(自動加載具有命名空間的類,適用於PHP5.3以上)的自動加載器,同時它也能按照PEAR命名規則加載類。它非常靈活可以基於子命名空間在不同的目錄中查詢要加載的類。你甚至可以為一個命名空間指定多個目錄。
require_once __DIR__.'/src/Symfony/Component/ClassLoader/UniversalClassLoader.php'; use Symfony\Component\ClassLoader\UniversalClassLoader; $loader = new UniversalClassLoader(); $loader->registerNamespaces(array( 'Symfony' => array(__DIR__.'/src', __DIR__.'/symfony/src'), 'Doctrine\\Common' => __DIR__.'/vendor/doctrine-common/lib', 'Doctrine\\DBAL' => __DIR__.'/vendor/doctrine-dbal/lib', 'Doctrine' => __DIR__.'/vendor/doctrine/lib', 'Monolog' => __DIR__.'/vendor/monolog/src', )); $loader->registerPrefixes(array( 'Twig_' => __DIR__.'/vendor/twig/lib', )); $loader->register();
如果你想獲取更加高的執行效率,可以選擇使用APC緩存版Universal類加載器。
2.Console 命令行工具
在創建web應用程序時使用命令行工具很方便,你可以想如下代碼一樣創建自己的命令行工具:
use Symfony\Component\Console\Application; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; $console = new Application(); $console ->register('ls') ->setDefinition(array( new InputArgument('dir', InputArgument::REQUIRED, 'Directory name'), )) ->setDescription('Displays the files in the given directory') ->setCode(function (InputInterface $input, OutputInterface $output) { $dir = $input->getArgument('dir'); $output->writeln(sprintf('Dir listing for <info>%s</info>', $dir)); }) ; $console->run();
3.YAML 一種現在很流行的配置格式。
use Symfony\Component\Yaml\Yaml; $array = Yaml::parse($file); print Yaml::dump($array);
4. Finder 優秀文件資源的操作接口。
use Symfony\Component\Finder\Finder; $finder = new Finder(); $iterator = $finder ->files() ->name('*.php') ->depth(0) ->size('>= 1K') ->in(__DIR__); foreach ($iterator as $file) { print $file->getRealpath()."\n"; }
你甚至可以用它獲取遠程服務器文件系統中的資源,比如獲取Amazon S3上的文件:
$s3 = new \Zend_Service_Amazon_S3($key, $secret); $s3->registerStreamWrapper("s3"); $finder = new Finder(); $finder->name('photos*')->size('< 100K')->date('since 1 hour ago'); foreach ($finder->in('s3://bucket-name') as $file) { print $file->getFilename()."\n"; }
5.Process 進程組件,你可以用來在一個外部進程中執行命令!下面例子是執行一個簡單的目錄列表命令並返回結果:
use Symfony\Component\Process\Process; $process = new Process('ls -lsa'); $process->setTimeout(3600); $process->run(); if (!$process->isSuccessful()) { throw new RuntimeException($process->getErrorOutput()); } print $process->getOutput();
如果你想監控執行過程,你可以給run方法傳入一個匿名方法:
use Symfony\Component\Process\Process; $process = new Process('ls -lsa'); $process->run(function ($type, $buffer) { if ('err' === $type) { echo 'ERR > '.$buffer; } else { echo 'OUT > '.$buffer; } });
6.DomCrawler jQuery的php版本!你可以用它導航定位HTML的DOM結構或者XML文檔。
use Symfony\Component\DomCrawler\Crawler; $crawler = new Crawler(); $crawler->addContent('<html><body><p>Hello World!</p></body></html>'); print $crawler->filterXPath('descendant-or-self::body/p')->text();
7.CssSelector 我們經常用XPath來訪問Dom結構,其實用Css 選擇器更加容易,這個組件就是把Css選擇器轉為XPath等效的東西。
use Symfony\Component\CssSelector\CssSelector; print CssSelector::toXPath('div.item > h4 > a');
所以你可以使用CssSelector 和DomCrawler來替代XPath:
use Symfony\Component\DomCrawler\Crawler; $crawler = new Crawler(); $crawler->addContent('<html><body><p>Hello World!</p></body></html>'); print $crawler->filter('body > p')->text();
8.HttpFoundation
該組件只是在PHP的相關web內容上面增加了一個面向對象層,包括Request,Response,Uploaded files,Cookies,Sessions...
use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; $request = Request::createFromGlobals(); echo $request->getPathInfo();
你用它可以很容易的創建自己的Request 和 Response:
$request = Request::create('/?foo=bar', 'GET'); echo $request->getPathInfo(); $response = new Response('Not Found', 404, array('Content-Type' => 'text/plain')); $response->send();
9.Routing
路由組件和Request對象是相互配合着把Request轉換為Response。
use Symfony\Component\HttpFoundation\Request; use Symfony\Component\Routing\Matcher\UrlMatcher; use Symfony\Component\Routing\RequestContext; use Symfony\Component\Routing\RouteCollection; use Symfony\Component\Routing\Route; $routes = new RouteCollection(); $routes->add('hello', new Route('/hello', array('controller' => 'foo'))); $context = new RequestContext(); // this is optional and can be done without a Request instance $context->fromRequest(Request::createFromGlobals()); $matcher = new UrlMatcher($routes, $context); $parameters = $matcher->match('/hello');
10.EventDispatcher
use Symfony\Component\EventDispatcher\EventDispatcher; use Symfony\Component\EventDispatcher\Event; $dispatcher = new EventDispatcher(); $dispatcher->addListener('event_name', function (Event $event) { // ... }); $dispatcher->dispatch('event_name');
11.DependencyInjection
use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Reference; $sc = new ContainerBuilder(); $sc ->register('foo', '%foo.class%') ->addArgument(new Reference('bar')) ; $sc->setParameter('foo.class', 'Foo'); $sc->get('foo');
12.HttpKernel
Http 內核組件提供了HTTP協議中最有活力的部分,以下面接口的形式定義展示,它也是Symfony2框架的核心。
interface HttpKernelInterface { /** * Handles a Request to convert it to a Response. * * @param Request $request A Request instance * * @return Response A Response instance */ function handle(Request $request, $type = self::MASTER_REQUEST, $catch = true); }
它接受一個Request輸入並返回一個Response輸出。 只要遵循這個接口規定,你就能使用Symfony2中所有的精彩內容。
下面使用Symfony2 組件來創建一個簡單的框架:
$routes = new RouteCollection(); $routes->add('hello', new Route('/hello', array('_controller' => function (Request $request) { return new Response(sprintf("Hello %s", $request->get('name'))); } ))); $request = Request::createFromGlobals(); $context = new RequestContext(); $context->fromRequest($request); $matcher = new UrlMatcher($routes, $context); $dispatcher = new EventDispatcher(); $dispatcher->addSubscriber(new RouterListener($matcher)); $resolver = new ControllerResolver(); $kernel = new HttpKernel($dispatcher, $resolver); $kernel->handle($request)->send();
ok, 這就是框架了!
如果想添加一個HTTP反向代理以獲取HTTP caching和ESI(Edge Side Includes)帶來的好處,那么這樣做!
$kernel = new HttpKernel($dispatcher, $resolver); $kernel = new HttpCache($kernel, new Store(__DIR__.'/cache'));
想對它做一下功能測試:
$client = new Client($kernel); $crawler = $client->request('GET', '/hello/Fabien'); $this->assertEquals('Fabien', $crawler->filter('p > span')->text());
想要一個好看的錯誤展示頁面?
$dispatcher->addSubscriber(new ExceptionListener(function (Request $request) { $msg = 'Something went wrong! ('.$request->get('exception')->getMessage().')'; return new Response($msg, 500); }));
你可以繼續發揮你的想象...
看看HttpKernelInterface 有多么強大!
總結一下,Symfony2 好像很牛啊,繼續研究研究!!!
關注URL: http://fabien.potencier.org/article/49/what-is-symfony2