# 升级指南
如果你打算从 Slim 2 升级到 Slim 3,这里有一些重要的变化,你必须清楚。
## 新的 PHP 版本要求
Slim 3 要求 PHP 5.5+
## 新的路由函数签名
```
$app->get('/', function (Request $req, Response $res, $args = []) {
return $res->withStatus(400)->write('Bad Request');
});
```
## 获取 _GET 和 _POST 变量
```
$app->get('/', function (Request $req, Response $res, $args = []) {
$myvar1 = $req->getParam('myvar'); //检查 _GET 和 _POST [不遵循 PSR 7]
$myvar2 = $req->getParsedBody()['myvar']; //检查 _POST [遵循 PSR 7]
$myvar3 = $req->getQueryParams()['myvar']; //检查 _GET [遵循 PSR 7]
});
```
## 钩子 / Hooks
Slim v3 不再有钩子的概念。You should consider reimplementing any functionality associated with the [default hooks in Slim v2](http://docs.slimframework.com/hooks/defaults/) as [middleware](/docs/concepts/middleware.html) instead. If you need the ability to apply custom hooks at arbitrary points in your code (for example, within a route), you should consider a third-party package such as [Symfony’s EventDispatcher](http://symfony.com/doc/current/components/event_dispatcher/introduction.html) or [Zend Framework’s EventManager](https://zend-eventmanager.readthedocs.org/en/latest/).
## 移除 HTTP 缓存
在 Slim v3 我们将 HTTP 缓存迁移到了单独的模块中: [Slim\Http\Cache](https://github.com/slimphp/Slim-HttpCache).
## 移除 Stop/Halt
Slim Core has removed Stop/Halt. In your applications, you should transition to using the withStatus() and withBody() methods.
## 重定向的改变
在 Slim v2.x 我们需要使用助手函数 $app->redirect(); 来触发重定向请求。在 Slim v3.x 中,我们可以使用响应类来做这事。
Example:
```
$app->get('/', function ($req, $res, $args) {
return $res->withStatus(302)->withHeader('Location', 'your-new-uri');
});
```
## 中间件签名
中间件的签名已经从一个类变成了函数。
新的签名:
```
use Psr\Http\Message\RequestInterface as Request;
use Psr\Http\Message\ResponseInterface as Response;
$app->add(function (Request $req, Response $res, callable $next) {
// Do stuff before passing along
$newResponse = $next($req, $res);
// Do stuff after route is rendered
return $newResponse; // continue
});
```
你仍然可以使用类来做签名:
```
namespace My;
use Psr\Http\Message\RequestInterface as Request;
use Psr\Http\Message\ResponseInterface as Response;
class Middleware
{
function __invoke(Request $req, Response $res, callable $next) {
// Do stuff before passing along
$newResponse = $next($req, $res);
// Do stuff after route is rendered
return $newResponse; // continue
}
}
// Register
$app->add(new My\Middleware());
// or
$app->add(My\Middleware::class);
```
## Middleware Execution
Application middleware is executed as Last In First Executed (LIFE).
## Flash Messages
Flash messages are no longer a part of the Slim v3 core but instead have been moved to seperate [Slim Flash](/docs/features/flash.html) package.
## Cookies
In v3.0 cookies has been removed from core. See [FIG Cookies](https://github.com/dflydev/dflydev-fig-cookies) for a PSR-7 compatible cookie component.
## Removal of Crypto
In v3.0 we have removed the dependency for crypto in core.
## New Router
Slim now utilizes [FastRoute](https://github.com/nikic/FastRoute), a new, more powerful router!
This means that the specification of route patterns has changed with named parameters now in braces and square brackets used for optional segments:
```
// named parameter:
$app->get('/hello/{name}', /*...*/);
// optional segment:
$app->get('/news[/{year}]', /*...*/);
```
## Route Middleware
The syntax for adding route middleware has changed slightly. In v3.0:
```
$app->get(…)->add($mw2)->add($mw1);
```
## urlFor() is now pathFor() in the router
`urlFor()` has been renamed `pathFor()` and can be found in the `router` object:
```
$app->get('/', function ($request, $response, $args) {
$url = $this->router->pathFor('home');
$response->write("<a href='$url'>Home</a>");
return $response;
})->setName('home');
```
Also, `pathFor()` is base path aware.
## Container and DI … Constructing
Slim uses Pimple as a Dependency Injection Container.
```
// index.php
$app = new Slim\App(
new \Slim\Container(
include '../config/container.config.php'
)
);
// Slim will grab the Home class from the container defined below and execute its index method.
// If the class is not defined in the container Slim will still contruct it and pass the container as the first arugment to the constructor!
$app->get('/', Home::class . ':index');
// In container.config.php
// We are using the SlimTwig here
return [
'settings' => [
'viewTemplatesDirectory' => '../templates',
],
'twig' => [
'title' => '',
'description' => '',
'author' => ''
],
'view' => function ($c) {
$view = new Twig(
$c['settings']['viewTemplatesDirectory'],
[
'cache' => false // '../cache'
]
);
// Instantiate and add Slim specific extension
$view->addExtension(
new TwigExtension(
$c['router'],
$c['request']->getUri()
)
);
foreach ($c['twig'] as $name => $value) {
$view->getEnvironment()->addGlobal($name, $value);
}
return $view;
},
Home::class => function ($c) {
return new Home($c['view']);
}
];
```
## PSR-7 Objects
### Request, Response, Uri & UploadFile are immutable.
This means that when you change one of these objects, the old instance is not updated.
```
// This is WRONG. The change will not pass through.
$app->add(function (Request $request, Response $response, $next) {
$request->withAttribute('abc', 'def');
return $next($request, $response);
});
// This is correct.
$app->add(function (Request $request, Response $response, $next) {
$request = $request->withAttribute('abc', 'def');
return $next($request, $response);
});
```
### Message bodies are streams
```
// ...
$image = __DIR__ . '/huge_photo.jpg';
$body = new Stream($image);
$response = (new Response())
->withStatus(200, 'OK')
->withHeader('Content-Type', 'image/jpeg')
->withHeader('Content-Length', filesize($image))
->withBody($body);
// ...
```
For text:
```
// ...
$response = (new Response())->getBody()->write('Hello world!')
// Or Slim specific: Not PSR-7 compliant.
$response = (new Response())->write('Hello world!');
// ...
```