Commit 34893c9e by Qiang Xue

Merge pull request #4472 from yii2-chinesization/master

translations for this week
parents 37354c0c 20c565f0
......@@ -39,7 +39,7 @@ Yii 2.0 权威指南
* **已定稿** [小部件(Widget)](structure-widgets.md)
* **已定稿** [模块(Module)](structure-modules.md)
* **编撰中** [前端资源(Asset)](structure-assets.md)
* **待定中** [扩展(extensions)](structure-extensions.md)
* **已定稿** [扩展(extensions)](structure-extensions.md)
请求处理
--------
......@@ -144,16 +144,6 @@ RESTful Web 服务
* **待定中** [验收测试](test-acceptance.md)
* **编撰中** [测试夹具](test-fixtures.md)
扩展 Yii
--------
* **编撰中** [创建扩展](extend-creating-extensions.md)
* **编撰中** [定制核心代码](extend-customizing-core.md)
* **编撰中** [使用第三方库](extend-using-libs.md)
* **待定中** [在第三方系统使用 Yii](extend-embedding-in-others.md)
* **待定中** [Yii 1.1 和 2.0 共用](extend-using-v1-v2.md)
* **编撰中** [使用依赖包管理器 Composer](extend-using-composer.md)
高级专题
--------
......@@ -167,6 +157,7 @@ RESTful Web 服务
* **编撰中** [性能优化](tutorial-performance-tuning.md)
* **待定中** [共享主机环境](tutorial-shared-hosting.md)
* **编撰中** [模板引擎](tutorial-template-engines.md)
* **已定稿** [集成第三方代码](tutorial-yii-integration.md)
小部件
------
......
片段缓存
================
片段缓存指的是缓存页面内容中的某个片段。例如,一个页面显示了逐年销售额的摘要表格,可以把表格缓存下来,以消除每次请求都要重新生成表格的耗时。片段缓存是基于[数据缓存](caching-data.md)实现的。
[视图](structure-views.md)中使用以下结构启用片段缓存:
```php
if ($this->beginCache($id)) {
// ... 在此生成内容 ...
$this->endCache();
}
```
调用 [[yii\base\View::beginCache()|beginCache()]] 和 [[yii\base\View::endCache()|endcache()]] 方法包裹内容生成逻辑。如果缓存中存在该内容,[[yii\base\View::beginCache()|beginCache()]] 方法将渲染内容并返回 false,因此将跳过内容生成逻辑。否则,内容生成逻辑被执行,一直执行到 [[yii\base\View::endCache()|endCache()]] 时,生成的内容将被捕获并存储在缓存中。
[[数据缓存]](caching-data.md)一样,每个片段缓存也需要全局唯一的 `$id` 标记。
## 缓存选项 <a name="caching-options"></a>
如果要为片段缓存指定额外配置项,请通过向 [[yii\base\View::beginCache()|beginCache()]] 方法第二个参数传递配置数组。在框架内部,该数组将被用来配置一个 [[yii\widget\FragmentCache]] 小部件用以实现片段缓存功能。
### 过期时间(duration) <a name="duration"></a>
或许片段缓存中最常用的一个配置选项就是 [[yii\widgets\FragmentCache::duration|duration]] 了。它指定了内容被缓存的秒数。以下代码缓存内容最多一小时:
```php
if ($this->beginCache($id, ['duration' => 3600])) {
// ... 在此生成内容 ...
$this->endCache();
}
```
如果该选项未设置,则默认为 0,永不过期。
### 依赖 <a name="dependencies"></a>
[[数据缓存]](caching-data.md)一样,片段缓存的内容一样可以设置缓存依赖。例如一段被缓存的文章,是否重新缓存取决于它是否被修改过。
通过设置 [[yii\widgets\FragmentCache::dependency|dependency]] 选项来指定依赖,该选项的值可以是一个 [[yii\caching\Dependency]] 类的派生类,也可以是创建缓存对象的配置数组。以下代码指定了一个片段缓存,它依赖于 `update_at` 字段是否被更改过的。
```php
$dependency = [
'class' => 'yii\caching\DbDependency',
'sql' => 'SELECT MAX(updated_at) FROM post',
];
if ($this->beginCache($id, ['dependency' => $dependency])) {
// ... 在此生成内容 ...
$this->endCache();
}
```
### 变化 <a name="variations"></a>
缓存的内容可能需要根据一些参数的更改而变化。例如一个 Web 应用支持多语言,同一段视图代码也许需要生成多个语言的内容。因此可以设置缓存根据应用当前语言而变化。
通过设置 [[yii\widgets\FragmentCache::variations|variations]] 选项来指定变化,该选项的值应该是一个标量,每个标量代表不同的变化系数。例如设置缓存根据当前语言而变化可以用以下代码:
```php
if ($this->beginCache($id, ['variations' => [Yii::$app->language]])) {
// ... 在此生成内容 ...
$this->endCache();
}
```
### 开关 <a name="toggling-caching"></a>
有时你可能只想在特定条件下开启片段缓存。例如,一个显示表单的页面,可能只需要在初次请求时缓存表单(通过 GET 请求)。随后请求所显示(通过 POST 请求)的表单不该使用缓存,因为此时表单中可能包含用户输入内容。鉴于此种情况,可以使用 [[yii\widgets\FragmentCache::enabled|enabled]] 选项来指定缓存开关,如下所示:
```php
if ($this->beginCache($id, ['enabled' => Yii::$app->request->isGet])) {
// ... 在此生成内容 ...
$this->endCache();
}
```
## 缓存嵌套 <a name="nested-caching"></a>
片段缓存可以被嵌套使用。一个片段缓存可以被另一个包裹。例如,评论被缓存在里层,同时整个评论的片段又被缓存在外层的文章中。以下代码展示了片段缓存的嵌套使用:
```php
if ($this->beginCache($id1)) {
// ...在此生成内容...
if ($this->beginCache($id2, $options2)) {
// ...在此生成内容...
$this->endCache();
}
// ...在此生成内容...
$this->endCache();
}
```
可以为嵌套的缓存设置不同的配置项。例如,内层缓存和外层缓存使用不同的过期时间。甚至当外层缓存的数据过期失效了,内层缓存仍然可能提供有效的片段缓存数据。但是,反之则不然。如果外层片段缓存没有过期而被视为有效,此时即使内层片段缓存已经失效,它也将继续提供同样的缓存副本。因此,你必须谨慎处理缓存嵌套中的过期时间和依赖,否则外层的片段很有可能返回的是不符合你预期的失效数据。
> 译者注:外层的失效时间应该短于内层,外层的依赖条件应该低于内层,以确保最小的片段,返回的是最新的数据。
## 动态内容 <a name="dynamic-content"></a>
使用片段缓存时,可能会遇到一大段较为静态的内容中有少许动态内容的情况。例如,一个显示着菜单栏和当前用户名的页面头部。还有一种可能是缓存的内容可能包含每次请求都需要执行的 PHP 代码(例如注册资源包的代码)。这两个问题都可以使用**动态内容**功能解决。
动态内容的意思是这部分输出的内容不该被缓存,即便是它被包裹在片段缓存中。为了使内容保持动态,每次请求都执行 PHP 代码生成,即使这些代码已经被缓存了。
可以在片段缓存中调用 [[yii\base\View::renderDynamic()]] 去插入动态内容,如下所示:
```php
if ($this->beginCache($id1)) {
// ...在此生成内容...
echo $this->renderDynamic('return Yii::$app->user->identity->name;');
// ...在此生成内容...
$this->endCache();
}
```
[[yii\base\View::renderDynamic()|renderDynamic()]] 方法接受一段 PHP 代码作为参数。代码的返回值被看作是动态内容。这段代码将在每次请求时都执行,无论其外层的片段缓存是否被存储。
HTTP 缓存
============
除了前面章节讲到的服务器端缓存外, Web 应用还可以利用客户端缓存去节省相同页面内容的生成和传输时间。
通过配置 [[yii\filters\HttpCache]] 过滤器,控制器操作渲染的内容就能缓存在客户端。[[yii\filters\HttpCache|HttpCache]] 过滤器仅对 `GET``HEAD` 请求生效,它能为这些请求设置三种与缓存有关的 HTTP 头。
* [[yii\filters\HttpCache::lastModified|Last-Modified]]
* [[yii\filters\HttpCache::etagSeed|Etag]]
* [[yii\filters\HttpCache::cacheControlHeader|Cache-Control]]
## `Last-Modified` 头 <a name="last-modified"></a>
`Last-Modified` 头使用时间戳标明页面自上次客户端缓存后是否被修改过。
通过配置 [[yii\filters\HttpCache::lastModified]] 属性向客户端发送 `Last-Modified` 头。该属性的值应该为 PHP callable 类型,返回的是页面修改时的 Unix 时间戳。该 callable 的参数和返回值应该如下:
```php
/**
* @param Action $action 当前处理的操作对象
* @param array $params “params” 属性的值
* @return integer 页面修改时的 Unix 时间戳
*/
function ($action, $params)
```
以下是使用 `Last-Modified` 头的示例:
```php
public function behaviors()
{
return [
[
'class' => 'yii\filters\HttpCache',
'only' => ['index'],
'lastModified' => function ($action, $params) {
$q = new \yii\db\Query();
return $q->from('post')->max('updated_at');
},
],
];
}
```
上述代码表明 HTTP 缓存只在 `index` 操作时启用。它会基于页面最后修改时间生成一个 `Last-Modified` HTTP 头。当浏览器第一次访问 `index` 页时,服务器将会生成页面并发送至客户端浏览器。之后客户端浏览器在页面没被修改期间访问该页,服务器将不会重新生成页面,浏览器会使用之前客户端缓存下来的内容。因此服务端渲染和内容传输都将省去。
## `ETag` 头 <a name="etag"></a>
“Entity Tag”(实体标签,简称 ETag)使用一个哈希值表示页面内容。如果页面被修改过,哈希值也会随之改变。通过对比客户端的哈希值和服务器端生成的哈希值,浏览器就能判断页面是否被修改过,进而决定是否应该重新传输内容。
通过配置 [[yii\filters\HttpCache::etagSeed]] 属性向客户端发送 `ETag` 头。该属性的值应该为 PHP callable 类型,返回的是一段种子字符用来生成 ETag 哈希值。该 callable 的参数和返回值应该如下:
```php
/**
* @param Action $action 当前处理的操作对象
* @param array $params “params” 属性的值
* @return string 一段种子字符用来生成 ETag 哈希值
*/
function ($action, $params)
```
以下是使用 `ETag` 头的示例:
```php
public function behaviors()
{
return [
[
'class' => 'yii\filters\HttpCache',
'only' => ['view'],
'etagSeed' => function ($action, $params) {
$post = $this->findModel(\Yii::$app->request->get('id'));
return serialize([$post->title, $post->content]);
},
],
];
}
```
上述代码表明 HTTP 缓存只在 `view` 操作时启用。它会基于用户请求的标题和内容生成一个 `ETag` HTTP 头。当浏览器第一次访问 `view` 页时,服务器将会生成页面并发送至客户端浏览器。之后客户端浏览器标题和内容没被修改在期间访问该页,服务器将不会重新生成页面,浏览器会使用之前客户端缓存下来的内容。因此服务端渲染和内容传输都将省去。
ETag 相比 `Last-Modified` 能实现更复杂和更精确的缓存策略。例如,当站点切换到另一个主题时可以使 ETag 失效。
复杂的 Etag 生成种子可能会违背使用 `HttpCache` 的初衷而引起不必要的性能开销,因为响应每一次请求都需要重新计算 Etag。请试着找出一个最简单的表达式去触发 Etag 失效。
> 注意:为了遵循 [RFC 2616, section 13.3.4(HTTP 协议)](http://tools.ietf.org/html/rfc2616#section-13.3.4),如果同时配置了 `ETag` 和 `Last-Modified` 头,`HttpCache` 将会同时发送它们,因此它们将被同时用于客户端的缓存失效校验。
## `Cache-Control` 头 <a name="cache-control"></a>
`Cache-Control` 头指定了页面的常规缓存策略。可以通过配置 [[yii\filters\HttpCache::cacheControlHeader]] 属性发送相应的头信息。默认发送以下头:
```
Cache-Control: public, max-age=3600
```
## 会话缓存限制器 <a name="session-cache-limiter"></a>
当页面使 session 时,PHP 将会按照 PHP.INI 中所设置的 `session.cache_limiter` 值自动发送一些缓存相关的 HTTP 头。这些 HTTP 头有可能会干扰你原本设置的 `HttpCache` 或让其失效。为了避免此问题,默认情况下 `HttpCache` 禁止自动发送这些头。想改变这一行为,可以配置 [[yii\filters\HttpCache::sessionCacheLimiter]] 属性。该属性接受一个字符串值,包括 `public``private``private_no_expire`,和 `nocache`。请参考 PHP 手册中的[缓存限制器](http://www.php.net/manual/en/function.session-cache-limiter.php)了解这些值的含义。
## SEO 影响 <a name="seo-implications"></a>
搜索引擎趋向于遵循站点的缓存头。因为一些爬虫的抓取频率有限制,启用缓存头可以可以减少重复请求数量,增加爬虫抓取效率(译者:大意如此,但搜索引擎的排名规则不了解,好的缓存策略应该是可以为用户体验加分的)。
缓存
=======
缓存是提升 Web 应用性能的简便有效的方式。通过将相对静态的数据存储到缓存并在收到请求时取回缓存,
应用程序便节省了每次都要重新生成这些数据所需的时间。
缓存是提升 Web 应用性能简便有效的方式。通过将相对静态的数据存储到缓存并在收到请求时取回缓存,应用程序便节省了每次重新生成这些数据所需的时间。
缓存可以发生在 Web 应用程序的任何层级任何位置。在服务器端,在较的低层面,缓存可能用于存储基础数据,
例如从数据库中取出的最新文章列表;在较高的层面,缓存可能用于存储一段或整个 Web 页面,例如最新文章
的渲染结果。在客户端,HTTP 缓存可能用于将最近访问的页面内容存储到浏览器缓存中。
缓存可以应用在 Web 应用程序的任何层级任何位置。在服务器端,在较的低层面,缓存可能用于存储基础数据,例如从数据库中取出的最新文章列表;在较高的层面,缓存可能用于存储一段或整个 Web 页面,例如最新文章的渲染结果。在客户端,HTTP 缓存可能用于将最近访问的页面内容存储到浏览器缓存中。
Yii 支持如上所有缓存机制:
......
页面缓存
============
页面缓存指的是在服务器端缓存整个页面的内容。随后当同一个页面被请求时,内容将从缓存中取出,而不是重新生成。
页面缓存由 [[yii\filters\PageCache]] 类提供支持,该类是一个[过滤器](structure-filters.md)。它可以像这样在控制器类中使用:
```php
public function behaviors()
{
return [
[
'class' => 'yii\filters\PageCache',
'only' => ['index'],
'duration' => 60,
'variations' => [
\Yii::$app->language,
],
'dependency' => [
'class' => 'yii\caching\DbDependency',
'sql' => 'SELECT COUNT(*) FROM post',
],
],
];
}
```
上述代码表示页面缓存只在 `index` 操作时启用,页面内容最多被缓存 60 秒,会随着当前应用的语言更改而变化。如果文章总数发生变化则缓存的页面会失效。
如你所见,页面缓存和[片段缓存](caching-fragment.md)极其相似。它们都支持 `duration``dependencies``variations``enabled` 配置选项。它们的主要区别是页面缓存是由[过滤器](structure-filters.md)实现,而片段缓存则是一个[小部件](structure-widgets.md)
你可以在使用页面缓存的同时,使用[片段缓存](caching-fragment.md)[动态内容](caching-fragment.md#dynamic-content)
别名(Aliases)
=======
别名(译者注:指路径/URL 别名,简称别名)用作代表文件路径和 URL,主要为了避免在代码中硬编码一些绝对路径和
URL。一个别名必须以 `@` 字符开头,以区别于传统的文件/目录路径或 URL。举栗,别名 `@yii`
指的是 Yii 框架本身的安装目录,而 `@web` 表示的是当前运行应用的根 URL(base URL)。
别名用来表示文件路径和 URL,这样就避免了在代码中硬编码一些绝对路径和 URL。一个别名必须以 `@` 字符开头,以区别于传统的文件路径和 URL。Yii 预定义了大量可用的别名。例如,别名 `@yii` 指的是 Yii 框架本身的安装目录,而 `@web` 表示的是当前运行应用的根 URL。
定义别名 <a name="defining-aliases"></a>
----------------
你可以调用 [[Yii::setAlias()]] 来给指定路径/URL 定义别名。栗子
你可以调用 [[Yii::setAlias()]] 来给文件路径或 URL 定义别名
```php
// 文件路径的别名
......@@ -19,22 +17,17 @@ Yii::setAlias('@foo', '/path/to/foo');
Yii::setAlias('@bar', 'http://www.example.com');
```
> 注意:别名所指向的文件路径或 URL 不一定是真实存在的文件或资源
> 注意:别名所指向的文件路径或 URL 不一定是真实存在的文件或资源。
用一个别名,你能通过在后面接续斜杠 `/` 以及若干路径片段得到一个新的别名(无需调用
[[Yii::setAlias()]])。我们把通过 [[Yii::setAlias()]] 定义的别名成为根别名
*root aliases*,而用他们衍生出去的别名成为衍生别名 *derived aliases*。比如,`@foo` 就是跟别名,而 `@foo/bar/file.php`
是一个衍生别名。
可以通过在一个别名后面加斜杠 `/` 和一至多个路径分段生成新别名(无需调用 [[Yii::setAlias()]])。我们把通过 [[Yii::setAlias()]] 定义的别名称为**根别名**,而用他们衍生出去的别名成为**衍生别名**。例如,`@foo` 就是跟别名,而 `@foo/bar/file.php` 是一个衍生别名。
你还可以用别名定义新别名(根别名与衍生别名均可):
你还可以用别名定义新别名(根别名与衍生别名均可):
```php
Yii::setAlias('@foobar', '@foo/bar');
```
根别名通常在 [引导(bootstrapping)](runtime-bootstrapping.md) 阶段定义。比如你可以在
[入口脚本](structure-entry-scripts.md) 里调用 [[Yii::setAlias()]]。为了方便起见呢,[应用主体(Application)](structure-applications.md)
提供了一个名为 `aliases` 的可写属性,你可以在应用[配置文件](concept-configurations.md)中设置它,就像这样:
根别名通常在[引导](runtime-bootstrapping.md)阶段定义。比如你可以在[入口脚本](structure-entry-scripts.md)里调用 [[Yii::setAlias()]]。为了方便起见,[应用](structure-applications.md)提供了一个名为 `aliases` 的可写属性,你可以在应用[配置](concept-configurations.md)中设置它,就像这样:
```php
return [
......@@ -50,25 +43,25 @@ return [
解析别名 <a name="resolving-aliases"></a>
-----------------
你可以调用 [[Yii::getAlias()]] 命令来解析一个根别名到他所对应的文件路径或 URL。同样的页面也可以用于解析衍生别名。比如:
你可以调用 [[Yii::getAlias()]] 命令来解析根别名到对应的文件路径或 URL。同样的页面也可以用于解析衍生别名。例如:
```php
echo Yii::getAlias('@foo'); // 显示:/path/to/foo
echo Yii::getAlias('@bar'); // 显示:http://www.example.com
echo Yii::getAlias('@foo/bar/file.php'); // 显示:/path/to/foo/bar/file.php
echo Yii::getAlias('@foo'); // 输出:/path/to/foo
echo Yii::getAlias('@bar'); // 输出:http://www.example.com
echo Yii::getAlias('@foo/bar/file.php'); // 输出:/path/to/foo/bar/file.php
```
由衍生别名所代指的路径/URL 是通过替换掉衍生别名中的根别名部分得到的。
由衍生别名所解析出的文件路径和 URL 是通过替换掉衍生别名中的根别名部分得到的。
> 注意:[[Yii::getAlias()]] 不检查结果路径/URL 所指向的资源是否真实存在。
> 注意:[[Yii::getAlias()]] 不检查结果路径/URL 所指向的资源是否真实存在。
根别名可能也会包含斜杠 `/` 字符。[[Yii::getAlias()]] 足够聪明,能知道一个别名中的哪个部分是根别名,因此能正确解析文件路径/URL。比如:
根别名可能也会包含斜杠 `/`[[Yii::getAlias()]] 足够智能到判断一个别名中的哪部分是根别名,因此能正确解析文件路径/URL。例如:
```php
Yii::setAlias('@foo', '/path/to/foo');
Yii::setAlias('@foo/bar', '/path2/bar');
Yii::getAlias('@foo/test/file.php'); // 显示:/path/to/foo/test/file.php
Yii::getAlias('@foo/bar/file.php'); // 显示:/path2/bar/file.php
echo Yii::getAlias('@foo/test/file.php'); // 输出:/path/to/foo/test/file.php
echo Yii::getAlias('@foo/bar/file.php'); // 输出:/path2/bar/file.php
```
`@foo/bar` 未被定义为根别名,最后一行语句会显示为 `/path/to/foo/bar/file.php`
......@@ -77,8 +70,7 @@ Yii::getAlias('@foo/bar/file.php'); // 显示:/path2/bar/file.php
使用别名 <a name="using-aliases"></a>
-------------
别名在 Yii 的很多地方都会被正确识别,而无需调用 [[Yii::getAlias()]]
来把它们转换为路径/URL。比如,[[yii\caching\FileCache::cachePath]] 能同时接受文件路径或是代表文件路径的别名,多亏了 `@` 前缀,它区分开了文件路径与别名。
别名在 Yii 的很多地方都会被正确识别,无需调用 [[Yii::getAlias()]] 来把它们转换为路径/URL。例如,[[yii\caching\FileCache::cachePath]] 能同时接受文件路径或是指向文件路径的别名,因为通过 `@` 前缀能区分它们。
```php
use yii\caching\FileCache;
......@@ -88,14 +80,13 @@ $cache = new FileCache([
]);
```
请关注下 API 文档了解属性或方法参数是否支持别名。
请关注 API 文档了解特定属性或方法参数是否支持别名。
预定义的别名 <a name="predefined-aliases"></a>
------------------
Yii 预定义了一系列别名来简化频繁引用常用路径和 URL的需求。
在核心框架中已经预定义有以下别名:
Yii 预定义了一系列别名来简化常用路径和 URL的使用:
- `@yii` - `BaseYii.php` 文件所在的目录(也被称为框架安装目录)
- `@app` - 当前运行的应用 [[yii\base\Application::basePath|根路径(base path)]]
......@@ -104,15 +95,13 @@ Yii 预定义了一系列别名来简化频繁引用常用路径和 URL的需求
- `@webroot` - 当前运行应用的 Web 入口目录
- `@web` - 当前运行应用的根 URL
`@yii` 别名是在[入口脚本](structure-entry-scripts.md)里包含 `Yii.php` 文件时定义的,其他的别名都是在[配置应用](concept-configurations.md)的时候,于应用的构造内定义的。
`@yii` 别名是在[入口脚本](structure-entry-scripts.md)里包含 `Yii.php` 文件时定义的,其他的别名都是在[配置应用](concept-configurations.md)的时候,于应用的构造方法内定义的。
扩展的别名 <a name="extension-aliases"></a>
-----------------
每一个通过 Composer 安装的 [扩展](structure-extensions.md) 都自动添加了一个别名。该别名会以该扩展在 `composer.json`
文件中所声明的根命名空间为名,且他直接代指该包的根目录。比如,如果你安装有 `yiisoft/yii2-jui` 扩展,你会自动得到
`@yii/jui` 别名,它定义于[引导启动](runtime-bootstrapping.md)阶段:
每一个通过 Composer 安装的 [扩展](structure-extensions.md) 都自动添加了一个别名。该别名会以该扩展在 `composer.json` 文件中所声明的根命名空间为名,且他直接代指该包的根目录。例如,如果你安装有 `yiisoft/yii2-jui` 扩展,会自动得到 `@yii/jui` 别名,它定义于[引导启动](runtime-bootstrapping.md)阶段:
```php
Yii::setAlias('@yii/jui', 'VendorPath/yiisoft/yii2-jui');
......
类自动加载(Autoloading)
=================
Yii 依靠[类自动加载机制(http://www.php.net/manual/en/language.oop5.autoload.php)来定位和包含所需的类文件。它提供一个高性能且完美支持[PSR-4 标准](https://github.com/php-fig/fig-standards/blob/master/proposed/psr-4-autoloader/psr-4-autoloader.md)[中文汉化](https://github.com/hfcorriez/fig-standards/blob/zh_CN/%E6%8E%A5%E5%8F%97/PSR-4-autoloader.md))的自动加载器。该自动加载器会在引入框架文件 `Yii.php` 时安装好。
Yii 依靠[类自动加载机制](http://www.php.net/manual/en/language.oop5.autoload.php)来定位和包含所需的类文件。它提供一个高性能且完美支持[PSR-4 标准](https://github.com/php-fig/fig-standards/blob/master/proposed/psr-4-autoloader/psr-4-autoloader.md)[中文汉化](https://github.com/hfcorriez/fig-standards/blob/zh_CN/%E6%8E%A5%E5%8F%97/PSR-4-autoloader.md))的自动加载器。该自动加载器会在引入框架文件 `Yii.php` 时安装好。
> 注意:为了简化叙述,本篇文档中我们只会提及类的自动加载。不过,要记得文中的描述同样也适用于接口和Trait(特质)的自动加载哦。
......
事件
======
事件可以将自定义代码“注入”到现有代码中的特定执行点。附加自定义代码到某个事件,当这个事件被触发时,这些代码就会自动执行。例如,邮件程序对象成功发出消息时可触发 `messageSent` 事件。如想追踪成功发送的消息,可以附加相应追踪代码到 `messageSent` 事件。
Yii 引入了名为 [[yii\base\Component]] 的基类以支持事件。如果一个类需要触发事件就应该继承 [[yii\base\Component]] 或其子类。
事件处理器(Event Handlers)
--------------
事件处理器是一个[PHP 回调函数](http://www.php.net/manual/en/language.types.callable.php),当它所附加到的事件被触发时它就会执行。可以使用以下回调函数之一:
- 字符串形式指定的 PHP 全局函数,如 `'trim'`
- 对象名和方法名数组形式指定的对象方法,如 `[$object, $method]`
- 类名和方法名数组形式指定的静态类方法,如 `[$class, $method]`
- 匿名函数,如 `function ($event) { ... }`
事件处理器的格式是:
```php
function ($event) {
// $event 是 yii\base\Event 或其子类的对象
}
```
通过 `$event` 参数,事件处理器就获得了以下有关事件的信息:
- [[yii\base\Event::name|event name]]:事件名
- [[yii\base\Event::sender|event sender]]:调用 `trigger()` 方法的对象
- [[yii\base\Event::data|custom data]]:附加事件处理器时传入的数据,默认为空,后文详述
附加事件处理器
----------------
调用 [[yii\base\Component::on()]] 方法来附加处理器到事件上。如:
```php
$foo = new Foo;
// 处理器是全局函数
$foo->on(Foo::EVENT_HELLO, 'function_name');
// 处理器是对象方法
$foo->on(Foo::EVENT_HELLO, [$object, 'methodName']);
// 处理器是静态类方法
$foo->on(Foo::EVENT_HELLO, ['app\components\Bar', 'methodName']);
// 处理器是匿名函数
$foo->on(Foo::EVENT_HELLO, function ($event) {
//事件处理逻辑
});
```
附加事件处理器时可以提供额外数据作为 [[yii\base\Component::on()]] 方法的第三个参数。数据在事件被触发和处理器被调用时能被处理器使用。如:
```php
// 当事件被触发时以下代码显示 "abc"
// 因为 $event->data 包括被传递到 "on" 方法的数据
$foo->on(Foo::EVENT_HELLO, function ($event) {
echo $event->data;
}, 'abc');
```
时间处理器顺序
-----------------
可以附加一个或多个处理器到一个事件。当事件被触发,已附加的处理器将按附加次序依次调用。如果某个处理器需要停止其后的处理器调用,可以设置 `$event` 参数的 [yii\base\Event::handled]] 属性为真,如下:
```php
$foo->on(Foo::EVENT_HELLO, function ($event) {
$event->handled = true;
});
```
默认新附加的事件处理器排在已存在处理器队列的最后。因此,这个处理器将在事件被触发时最后一个调用。在处理器队列最前面插入新处理器将使该处理器最先调用,可以传递第四个参数 `$append` 为假并调用 [[yii\base\Component::on()]] 方法实现:
``php
$foo->on(Foo::EVENT_HELLO, function ($event) {
// 这个处理器将被插入到处理器队列的第一位...
}, $data, false);
```
触发事件
----------
事件通过调用 [[yii\base\Component::trigger()]] 方法触发,此方法须传递**事件名**,还可以传递一个事件对象,用来传递参数到事件处理器。如:
```php
namespace app\components;
use yii\base\Component;
use yii\base\Event;
class Foo extends Component
{
const EVENT_HELLO = 'hello';
public function bar()
{
$this->trigger(self::EVENT_HELLO);
}
}
```
以上代码当调用 `bar()` ,它将触发名为 `hello` 的事件。
> 提示:推荐使用类常量来表示事件名。上例中,常量 `EVENT_HELLO` 用来表示 `hello` 。这有两个好处。第一,它可以防止拼写错误并支持 IDE 的自动完成。第二,只要简单检查常量声明就能了解一个类支持哪些事件。
有时想要在触发事件时同时传递一些额外信息到事件处理器。例如,邮件程序要传递消息信息到 `messageSent` 事件的处理器以便处理器了解哪些消息被发送了。为此,可以提供一个事件对象作为 [[yii\base\Component::trigger()]] 方法的第二个参数。这个事件对象必须是 [[yii\base\Event]] 类或其子类的实例。如:
```php
namespace app\components;
use yii\base\Component;
use yii\base\Event;
class MessageEvent extends Event
{
public $message;
}
class Mailer extends Component
{
const EVENT_MESSAGE_SENT = 'messageSent';
public function send($message)
{
// ...发送 $message 的逻辑...
$event = new MessageEvent;
$event->message = $message;
$this->trigger(self::EVENT_MESSAGE_SENT, $event);
}
}
```
当 [[yii\base\Component::trigger()]] 方法被调用时,它将调用所有附加到命名事件(trigger 方法第一个参数)的事件处理器。
移除事件处理器
---------------
从事件移除处理器,调用 [[yii\base\Component::off()]] 方法。如:
```php
// 处理器是全局函数
$foo->off(Foo::EVENT_HELLO, 'function_name');
// 处理器是对象方法
$foo->off(Foo::EVENT_HELLO, [$object, 'methodName']);
// 处理器是静态类方法
$foo->off(Foo::EVENT_HELLO, ['app\components\Bar', 'methodName']);
// 处理器是匿名函数
$foo->off(Foo::EVENT_HELLO, $anonymousFunction);
```
注意当匿名函数附加到事件后一般不要尝试移除匿名函数,除非你在某处存储了它。以上示例中,假设匿名函数存储为变量 `$anonymousFunction` 。
移除事件的全部处理器,简单调用 [[yii\base\Component::off()]] 即可,不需要第二个参数:
```php
$foo->off(Foo::EVENT_HELLO);
```
类级别的事件处理器
-------------------
以上部分,我们叙述了在**实例级别**如何附加处理器到事件。有时想要一个类的所有实例而不是一个指定的实例都响应一个被触发的事件,并不是一个个附加事件处理器到每个实例,而是通过调用静态方法 [[yii\base\Event::on()]] 在**类级别**附加处理器。
例如,[活动记录](db-active-record.md)对象要在每次往数据库新增一条新记录时触发一个 [[yii\base\ActiveRecord::EVENT_AFTER_INSERT]] 事件。要追踪每个[活动记录](db-active-record.md)对象的新增记录完成情况,应如下写代码:
```php
use Yii;
use yii\base\Event;
use yii\db\ActiveRecord;
Event::on(ActiveRecord::className(), ActiveRecord::EVENT_AFTER_INSERT, function ($event) {
Yii::trace(get_class($event->sender) . ' is inserted');
});
```
每当 [[yii\base\ActiveRecord|ActiveRecord]] 或其子类的实例触发 [[yii\base\ActiveRecord::EVENT_AFTER_INSERT|EVENT_AFTER_INSERT]] 事件时,这个事件处理器都会执行。在这个处理器中,可以通过 `$event->sender` 获取触发事件的对象。
当对象触发事件时,它首先调用实例级别的处理器,然后才会调用类级别处理器。
可调用静态方法[[yii\base\Event::trigger()]]来触发一个**类级别**事件。类级别事件不与特定对象相关联。因此,它只会引起类级别事件处理器的调用。如:
```php
use yii\base\Event;
Event::on(Foo::className(), Foo::EVENT_HELLO, function ($event) {
echo $event->sender; // 显示 "app\models\Foo"
});
Event::trigger(Foo::className(), Foo::EVENT_HELLO);
```
注意这种情况下 `$event->sender` 指向触发事件的类名而不是对象实例。
> 注意:因为类级别的处理器响应类和其子类的所有实例触发的事件,必须谨慎使用,尤其是底层的基类,如 [[yii\base\Object]]。
移除类级别的事件处理器只需调用[[yii\base\Event::off()]],如:
```php
// 移除 $handler
Event::off(Foo::className(), Foo::EVENT_HELLO, $handler);
// 移除 Foo::EVENT_HELLO 事件的全部处理器
Event::off(Foo::className(), Foo::EVENT_HELLO);
```
全局事件
-------------
所谓**全局事件**实际上是一个基于以上叙述的事件机制的戏法。它需要一个全局可访问的单例,如[应用](structure-applications.md)实例。
事件触发者不调用其自身的 `trigger()` 方法,而是调用单例的 `trigger()` 方法来触发全局事件。类似地,事件处理器被附加到单例的事件。如:
```php
use Yii;
use yii\base\Event;
use app\components\Foo;
Yii::$app->on('bar', function ($event) {
echo get_class($event->sender); // 显示 "app\components\Foo"
});
Yii::$app->trigger('bar', new Event(['sender' => new Foo]));
```
全局事件的一个好处是当附加处理器到一个对象要触发的事件时,不需要产生该对象。相反,处理器附加和事件触发都通过单例(如应用实例)完成。
然而,因为全局事件的命名空间由各方共享,应合理命名全局事件,如引入一些命名空间(例:"frontend.mail.sent", "backend.mail.sent")。
\ No newline at end of file
服务定位器(Service Locator)
服务定位器
===============
服务定位器是一个了解如何提供各种应用所需的服务(或组件)的对象。在一个服务定位器中,每一个组件都只有一个单独的实例,并通过
ID 唯一地标识。用这个 ID 就能从服务定位器中得到这个组件。
服务定位器是一个了解如何提供各种应用所需的服务(或组件)的对象。在服务定位器中,每个组件都只有一个单独的实例,并通过ID 唯一地标识。用这个 ID 就能从服务定位器中得到这个组件。
在 Yii 中,服务定位器[[yii\di\ServiceLocator]] 或其子类的一个实例。
在 Yii 中,服务定位器是 [[yii\di\ServiceLocator]] 或其子类的一个实例。
最最常用的服务定位器一般是 *application(应用)* 对象,可以通过 `\Yii::$app` 访问。它所提供的服务被称为
*application components(应用组件)*,比如:`request``response``urlManager`(分别是请求、响应、Url 管理器)组件。你可以通过服务定位器所提供的功能,非常容易地配置这些组件,或甚至是用你自己的实现替换掉他们。
最常用的服务定位器是**application(应用)**对象,可以通过 `\Yii::$app` 访问。它所提供的服务被称为**application components(应用组件)**,比如:`request``response``urlManager` 组件。可以通过服务定位器所提供的功能,非常容易地配置这些组件,或甚至是用你自己的实现替换掉他们。
除了 Application 对象,每一个模块对象本身也是一个服务定位器。
除了 application 对象,每个模块对象本身也是一个服务定位器。
要使用一个服务定位器,第一步是要注册相关组件。组件可以通过 [[yii\di\ServiceLocator::set()]]
方法进行注册。以下的方法展示了注册组件的不同方法:
要使用服务定位器,第一步是要注册相关组件。组件可以通过 [[yii\di\ServiceLocator::set()]] 方法进行注册。以下的方法展示了注册组件的不同方法:
```php
use yii\di\ServiceLocator;
......@@ -48,15 +45,11 @@ $cache = $locator->get('cache');
$cache = $locator->cache;
```
如上文所示, [[yii\di\ServiceLocator]] 允许你通过组件 ID 像访问一个属性值那样访问一个组件。当你第一次访问某组件时,
[[yii\di\ServiceLocator]] 会通过该组件的注册信息创建一个该组件的实例,并返回它。之后,如果再次访问,则服务定位器会返回同一个实例。
如上所示, [[yii\di\ServiceLocator]] 允许通过组件 ID 像访问一个属性值那样访问一个组件。当你第一次访问某组件时,[[yii\di\ServiceLocator]] 会通过该组件的注册信息创建一个该组件的实例,并返回它。之后,如果再次访问,则服务定位器会返回同一个实例。
你可以通过 [[yii\di\ServiceLocator::has()]] 检查某组件 ID 是否被注册。
若你用一个无效的 ID 调用 [[yii\di\ServiceLocator::get()]],则会抛出一个异常。
你可以通过 [[yii\di\ServiceLocator::has()]] 检查某组件 ID 是否被注册。若你用一个无效的 ID 调用 [[yii\di\ServiceLocator::get()]],则会抛出一个异常。
因为服务定位器,经常会在创建时附带[配置信息](concept-configurations.md),因此我们提供了一个可写的属性,名为
[[yii\di\ServiceLocator::setComponents()|components]],这样就可以配置该属性,或一次性注册多个组件。下面的代码展示了如何用一个配置数组,配置一个应用并注册
"db","cache" 和 "search" 三个组件:
因为服务定位器,经常会在创建时附带[配置信息](concept-configurations.md),因此我们提供了一个可写的属性,名为 [[yii\di\ServiceLocator::setComponents()|components]],这样就可以配置该属性,或一次性注册多个组件。下面的代码展示了如何用一个配置数组,配置一个应用并注册"db","cache" 和 "search" 三个组件:
```php
return [
// ...
......
......@@ -11,7 +11,7 @@ Oracle
MSSQL: version 2012 或更高版本,如需使用 LIMIT/OFFSET。
配置
开始使用数据库首先需要配置数据库连接组件,通过添加 db 组件到应用配置实现("基础的" web 应用是 config/web.php),如下所示:
开始使用数据库首先需要配置数据库连接组件,通过添加 db 组件到应用配置实现("基础的" Web 应用是 config/web.php),如下所示:
return [
// ...
......
Yii 是什么
===========
Yii 是一个高性能,基于组件的 PHP 框架,用于快速开发现代 Web 应用程序。名字 Yii (读作 `易`)在中文里有“极致简单与不断变化”两重含义,也可看作 **Yes It Is**! 的缩写。
Yii 是一个高性能,基于组件的 PHP 框架,用于快速开发现代 Web 应用程序。名字 Yii (读作 `易`)在中文里有 “极致简单与不断演变” 两重含义,也可看作 **Yes It Is**! 的缩写。
Yii 最适合做什么?
......
......@@ -3,7 +3,7 @@
你可以通过两种方式安装 Yii:使用 [Composer](http://getcomposer.org/) 或下载一个归档文件。推荐使用前者,这样只需执行一条简单的命令就可以安装新的[扩展](extend-creating-extensions.md)或更新 Yii 了。
> 注意:和 Yii 1 不同,以标准方式安装 Yii 2 时会同时下载并安装框架本身和一个应用程序骨架。
> 注意:和 Yii 1 不同,以标准方式安装 Yii 2 时会同时下载并安装框架本身和一个应用程序的基本骨架。
通过 Composer 安装 <a name="installing-via-composer"></a>
......@@ -22,13 +22,13 @@ Composer 安装后,切换到一个可通过 Web 访问的目录,执行如下
composer create-project --prefer-dist yiisoft/yii2-app-basic basic
如上命令会将 Yii 安装在一个名为 `basic` 的目录中。
如上命令会将 Yii 安装在名为 `basic` 的目录中。
> 技巧:如果你想安装 Yii 的最新开发版本,可以使用如下命令,它添加了一个 [stability 选项](https://getcomposer.org/doc/04-schema.md#minimum-stability):
> 技巧:如果你想安装 Yii 的最新开发版本,可以使用如下命令,它添加了一个 [stability 选项](https://getcomposer.org/doc/04-schema.md#minimum-stability)([中文版](https://github.com/5-say/composer-doc-cn/blob/master/cn-introduction/04-schema.md#minimum-stability)):
>
> composer create-project --prefer-dist --stability=dev yiisoft/yii2-app-basic basic
>
> 注意,Yii 的开发版不应该用于生产环境中,它可能会破坏运行中的代码。
> 注意,Yii 的开发版(dev 版)不应该用于生产环境中,它可能会破坏运行中的代码。
通过归档文件安装 <a name="installing-from-archive-file"></a>
......@@ -38,20 +38,26 @@ Composer 安装后,切换到一个可通过 Web 访问的目录,执行如下
1.[yiiframework.com](http://www.yiiframework.com/download/yii2-basic) 下载归档文件。
2. 将下载的文件解压缩到 Web 目录中。
3. 修改 `config/web.php` 文件,给 `cookieValidationKey` 配置项添加一个密钥(若你通过 Composer 安装,则此步骤会自动完成):
```php
// !!! 在下面插入一段密钥(若为空) - 以供 cookie validation 的需要
'cookieValidationKey' => '在此处输入你的密钥',
```
其他安装方式 <a name="other-installation-options"></a>
--------------------------
上文介绍了两种安装 Yii 的方法,安装的同时也会创建一个立即可用的 Web 应用程序。对于小的项目或学习,这是一个很好的起点。
上文介绍了两种安装 Yii 的方法安装的同时也会创建一个立即可用的 Web 应用程序对于小的项目或用于学习上手这都是一个不错的起点
但是还可以有其他的安装方式
但是其他的安装方式也存在
* 如果你只想安装核心框架,然后从头开始创建一个应用程序,可以参考[从头构建自定义模版](tutorial-start-from-scratch.md)一节的介绍。
* 如果你要开发一个更复杂的应用,更好的地适用于团队开发环境的,可以考虑安装[高级应用模版](tutorial-advanced-app.md)
* 如果你只想安装核心框架然后从零开始构建整个属于你自己的应用程序模版可以参考[从头构建自定义模版](tutorial-start-from-scratch.md)一节的介绍
* 如果你要开发一个更复杂的应用可以更好地适用于团队开发环境的可以考虑安装[高级应用模版](tutorial-advanced-app.md)
检查安装 <a name="verifying-installation"></a>
验证安装的结果 <a name="verifying-installation"></a>
--------------------------
安装完成后就可以使用浏览器通过如下 URL 访问刚安装完的 Yii 应用了
......@@ -60,11 +66,11 @@ Composer 安装后,切换到一个可通过 Web 访问的目录,执行如下
http://localhost/basic/web/index.php
```
这个 URL 假设你将 Yii 安装到了一个位于 Web 文档根目录下的 `basic` 目录中,且该 Web 服务器正运行在你自己的电脑上 `localhost`)。你可能需要将其调整为适应自己的安装环境。
这个 URL 假设你将 Yii 安装到了一个位于 Web 文档根目录下的 `basic` 目录中,且该 Web 服务器正运行在你自己的电脑上(`localhost`)。你可能需要将其调整为适应自己的安装环境。
![Yii 安装成功](images/start-app-installed.png)
你应该可以在浏览器中看到如上所示的 “Congratulations!” 页面。如果没有,请检查你安装的 PHP 环境是否符合 Yii 的需求,可以通过如下任意一种方式检查是否满足最小需求:
你应该可以在浏览器中看到如上所示的 “Congratulations!” 页面。如果没有,请通过以下任意一种方式,检查当前 PHP 环境是否满足 Yii 最基本需求:
* 通过浏览器访问 URL `http://localhost/basic/requirements.php`
* 执行如下命令:
......@@ -74,21 +80,21 @@ http://localhost/basic/web/index.php
php requirements.php
```
你需要配置好 PHP 安装环境,使其符合 Yii 的最小需求。最重要的是需要有 PHP 5.4 以上版本。如果应用需要用到数据库,那还要安装 [PDO PHP 扩展](http://www.php.net/manual/en/pdo.installation.php) 和相应的数据库驱动(例如访问 MySQL 数据库所需的 `pdo_mysql`)。
你需要配置好 PHP 安装环境,使其符合 Yii 的最小需求。主要是需要 PHP 5.4 以上版本。如果应用需要用到数据库,那还要安装 [PDO PHP 扩展](http://www.php.net/manual/zh/pdo.installation.php) 和相应的数据库驱动(例如访问 MySQL 数据库所需的 `pdo_mysql`)。
配置 Web 服务器 <a name="configuring-web-servers"></a>
-----------------------
>补充:如果你现在只是要试用 Yii 而不是要将其部署到生产环境中的服务器上,本小节可以跳过。
>补充:如果你现在只是要试用 Yii 而不是将其部署到生产环境中,本小节可以跳过。
通过上述方法安装的应用程序在 Windows,Max OS X, Linux 中的 [Apache HTTP 服务器](http://httpd.apache.org/)或 [Nginx HTTP 服务器](http://nginx.org/) 上都可以直接运行。
通过上述方法安装的应用程序在 Windows,Max OS X,Linux 中的 [Apache HTTP 服务器](http://httpd.apache.org/)或 [Nginx HTTP 服务器](http://nginx.org/) 上都可以直接运行。
在生产环境的服务器上,你可能会想配置服务器让应用程序可以通过 URL `http://www.example.com/index.php` 访问而不是 `http://www.example.com/basic/web/index.php`。这种配置需要将 Web 服务器的文档根目录指向 `basic/web` 目录。可能你还会想隐藏掉 URL 中的 `index.php`,具体细节在 [URL 解析和生成](runtime-url-handling.md) 一章中有介绍,你将学到如何配置 Apache 或 Nginx 服务器实现这些目标。
>补充:将 `basic/web` 设置为文档根目录,可以防止终端用户访问 `basic/web` 相邻目录中的私有应用程序代码和敏感数据文件。禁止对其他目录的访问是一个切实可行的安全改进。
>补充:将 `basic/web` 设置为文档根目录,可以防止终端用户访问 `basic/web` 相邻目录中的私有应用代码和敏感数据文件。禁止对其他目录的访问是一个不错的安全改进。
>补充:如果你的应用程序将来要运行在共享的主机环境中,没有权限修改它的 Web 服务器配置,你依然可以调整应用程序的结构提升安全性。详情请参考[共享主机环境](tutorial-shared-hosting.md) 一章。
>补充:如果你的应用程序将来要运行在共享虚拟主机环境中,没有修改其 Web 服务器配置的权限,你依然可以通过调整应用的结构来提升安全性。详情请参考[共享主机环境](tutorial-shared-hosting.md) 一章。
### 推荐使用的 Apache 配置 <a name="recommended-apache-configuration"></a>
......@@ -137,7 +143,7 @@ server {
try_files $uri $uri/ /index.php?$args;
}
# 给这段解除注释,能够避免 Yii 接管不存在文件的处理过程(404)
# 若取消下面这段的注释,可避免 Yii 接管不存在文件的处理过程(404)
#location ~ \.(js|css|png|jpg|gif|swf|ico|pdf|mov|fla|zip|rar)$ {
# try_files $uri =404;
#}
......@@ -155,6 +161,6 @@ server {
}
```
使用该配置时,你还应该在 `php.ini` 文件中设置 `cgi.fix_pathinfo=0` 以避免很多不必要的 `stat()` 系统调用。
使用该配置时,你还应该在 `php.ini` 文件中设置 `cgi.fix_pathinfo=0` ,能避免掉很多不必要的 `stat()` 系统调用。
还要注意当运行一个 HTTPS 服务器时,需要添加 `fastcgi_param HTTPS on;` 一行,这样 Yii 才能正确地判断连接是否安全。
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment