com doc/zh: Sync with en: language/attributes.xml

[email protected] (Dai Jie) Wed, 30 Dec 2020 13:15:37 +0000
Newsgroups php.doc.zh
Message-ID <[email protected]>
Commit:    6269f2b0c62874e003d9d7c6fe0f6af795d1cfbb
Author:    daijie <[email protected]>         Wed, 30 Dec 2020 21:15:37 +0800
Parents:   51d5438ab8c2d5a5f62707fc07bd6acf79b958e1
Branches:  master

Link:       http://git.php.net/?p=doc/zh.git;a=commitdiff;h=6269f2b0c62874e003d9d7c6fe0f6af795d1cfbb

Log:
Sync with en

Changed paths:
  A  language/attributes.xml
diff_6269f2b0c62874e003d9d7c6fe0f6af795d1cfbb.txt (text/plain, 9.4 KB)
diff --git a/language/attributes.xml b/language/attributes.xml
new file mode 100755
index 00000000..5e4fea34
--- /dev/null
+++ b/language/attributes.xml
@@ -0,0 +1,368 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- $Revision: $ -->
+<!-- EN-Revision: 352158 Maintainer: daijie Status: ready -->
+<!-- Reviewed: no -->
+
+ <chapter xml:id="language.attributes" xmlns="http://docbook.org/ns/docbook">
+  <title>注解</title>
+  <sect1 xml:id="language.attributes.overview">
+   <title>注解概览</title>
+   <?phpdoc print-version-for="attributes"?>
+
+   <para>
+    注解功能使得代码中的声明部分都可以添加结构化、机器可读的元数据,
+    注解的目标可以是类、方法、函数、参数、属性、类常量。
+    
+    通过 <link linkend="book.reflection">反射 API</link> 可在运行时获取注解所定义的元数据。
+    因此注解可以成为直接嵌入代码的配置式语言。
+   </para>
+
+   <para>
+    通过注解的使用,在应用中实现功能、使用功能可以相互解耦。
+    某种程度上讲,它可以和接口(interface)与其实现(implementation)相比较。
+    但接口与实现是代码相关的,注解则与声明额外信息和配置相关。
+    接口可以通过类来实现,而注解也可以声明到方法、函数、参数、属性、类常量中。
+    因此它们比接口更灵活。
+   </para>
+
+    <para>
+     注解使用的一个简单例子:将接口(interface)的可选方法改用注解实现。
+     我们假设接口 <literal>ActionHandler</literal> 代表了应用的一个操作:
+     部分 action handler 的实现需要 setup,部分不需要。
+     我们可以使用注解,而不用要求所有类必须实现 <literal>ActionHandler</literal> 
+     接口并实现 <literal>setUp()</literal> 方法。
+     因此带来一个好处——可以多次使用注解。
+    </para>
+
+   <example>
+    <title>用注解实现接口的可选方法</title>
+     <programlisting role="php">
+<![CDATA[
+<?php
+interface ActionHandler
+{
+    public function execute();
+}
+
+#[Attribute]
+class SetUp {}
+
+class CopyFile implements ActionHandler
+{
+    public string $fileName;
+    public string $targetDirectory;
+
+    #[SetUp]
+    public function fileExists()
+    {
+        if (!file_exists($this->fileName)) {
+            throw new RuntimeException("File does not exist");
+        }
+    }
+
+    #[SetUp]
+    public function targetDirectoryExists()
+    {
+        mkdir($this->targetDirectory);
+    }
+
+    public function execute()
+    {
+        copy($this->fileName, $this->targetDirectory . '/' . basename($this->fileName));
+    }
+}
+
+function executeAction(ActionHandler $actionHandler)
+{
+    $reflection = new ReflectionObject($actionHandler);
+
+    foreach ($reflection->getMethods() as $method) {
+        $attributes = $method->getAttributes(SetUp::class);
+
+        if (count($attributes) > 0) {
+            $methodName = $method->getName();
+
+            $actionHandler->$methodName();
+        }
+    }
+
+    $actionHandler->execute();
+}
+
+$copyAction = new CopyFile();
+$copyAction->fileName = "/tmp/foo.jpg";
+$copyAction->targetDirectory = "/home/user";
+
+executeAction($copyAction);
+]]>
+     </programlisting>
+    </example>
+  </sect1>
+
+  <sect1 xml:id="language.attributes.syntax">
+   <title>注解语法</title>
+
+   <para>
+    注解语法包含以下几部分。
+    首先,注解声明总是以 <literal>#[</literal> 开头,以
+    <literal>]</literal> 结尾来包围。
+    内部则是一个或以逗号包含的多个注解。
+    注解的名称按 <link linkend="language.namespaces.basics">使用命名空间:基础</link> 
+    章节中描述,可以是非限定、限定、完全限定的名称。
+    注解的参数是可以选的,以常见的括号<literal>()</literal>包围。
+    注解的参数可以是字面值或者常量表达式。
+    它同时接受位置参数和命名参数两种语法。
+   </para>
+
+   <para>
+    通过反射 API 请求注解实例时,注解的名称会被解析到一个类,注解的参数则传入该类的构造器中。
+    因此每个注解都需要引入一个类。
+   </para>
+
+   <example>
+    <title>注解语法</title>
+
+    <programlisting role="php">
+<![CDATA[
+<?php
+// a.php
+namespace MyExample;
+
+use Attribute;
+
+#[Attribute]
+class MyAttribute
+{
+    const VALUE = 'value';
+
+    private $value;
+
+    public function __construct($value = null)
+    {
+        $this->value = $value;
+    }
+}
+
+// b.php
+
+namespace Another;
+
+use MyExample\MyAttribute;
+
+#[MyAttribute]
+#[\MyExample\MyAttribute]
+#[MyAttribute(1234)]
+#[MyAttribute(value: 1234)]
+#[MyAttribute(MyAttribute::VALUE)]
+#[MyAttribute(array("key" => "value"))]
+#[MyAttribute(100 + 200)]
+class Thing
+{
+}
+
+#[MyAttribute(1234), MyAttribute(5678)]
+class AnotherThing
+{
+}
+]]>
+    </programlisting>
+   </example>
+  </sect1>
+
+
+  <sect1 xml:id="language.attributes.reflection">
+   <title>使用反射 API 读取注解</title>
+
+   <para>
+    反射 API 提供了 <function>getAttributes</function> 方法,
+    类、方法、函数、参数、属性、类常量的反射对象可通过它获取相应的注解。
+    该方法返回了 <classname>ReflectionAttribute</classname> 实例的数组,
+    可用于查询注解名称、参数、也可以实例化一个注解。
+   </para>
+
+   <para>
+    实例和反射注解的分离使得程序员增加了在丢失反射类、类型错误、丢失参数等情况下的处理能力,也能处理错误。
+    只有调用 <function>newInstance</function> 后,注解类的对象才会以验证过匹配的参数来实例化。
+   </para>
+
+   <example>
+    <title>通过反射 API 读取注解</title>
+
+    <programlisting role="php">
+<![CDATA[
+<?php
+
+#[Attribute]
+class MyAttribute
+{
+    public $value;
+
+    public function __construct($value)
+    {
+        $this->value = $value;
+    }
+}
+
+#[MyAttribute(value: 1234)]
+class Thing
+{
+}
+
+function dumpAttributeData($reflection) {
+    $attributes = $reflection->getAttributes();
+
+    foreach ($attributes as $attribute) {
+       var_dump($attribute->getName());
+       var_dump($attribute->getArguments());
+       var_dump($attribute->newInstance());
+    }
+}
+
+dumpAttributeData(new ReflectionClass(Thing::class));
+/*
+string(11) "MyAttribute"
+array(1) {
+  ["value"]=>
+  int(1234)
+}
+object(MyAttribute)#3 (1) {
+  ["value"]=>
+  int(1234)
+}
+*/
+
+]]>
+    </programlisting>
+   </example>
+
+   <para>
+    Instead of iterating all attributes on the reflection instance, only those
+    of a particular attribute class can be
+    retrieved by passing the searched attribute class name as argument.
+   </para>
+
+   <example>
+    <title>使用反射 API 读取指定的注解</title>
+
+    <programlisting role="php">
+<![CDATA[
+<?php
+
+function dumpMyAttributeData($reflection) {
+    $attributes = $reflection->getAttributes(MyAttribute::class);
+
+    foreach ($attributes as $attribute) {
+       var_dump($attribute->getName());
+       var_dump($attribute->getArguments());
+       var_dump($attribute->newInstance());
+    }
+}
+
+dumpAttributeData(new ReflectionClass(Thing::class));
+]]>
+     </programlisting>
+    </example>
+  </sect1>
+
+  <sect1 xml:id="language.attributes.classes">
+   <title>声明注解类</title>
+
+   <para>
+    虽然没有严格要求,推荐为每个注解创建一个实际的类。
+    在这个最简单的例子中,通过 use 语法从全局命名空间引入 <literal>#[Attribute]</literal> 注解所需要全空的类。
+   </para>
+
+  <example>
+   <title>目标限定使用的注解</title>
+
+   <programlisting role="php">
+<![CDATA[
+<?php
+
+namespace Example;
+
+use Attribute;
+
+#[Attribute]
+class MyAttribute
+{
+}
+]]>
+   </programlisting>
+  </example>
+
+  <para>
+   要限制指定注解的声明类型,可为 <literal>#[Attribute]</literal> 注解第一个参数传入字节位掩码设置。
+  </para>
+
+  <example>
+   <title>简单的 Attribute 类</title>
+
+   <programlisting role="php">
+<![CDATA[
+<?php
+
+namespace Example;
+
+use Attribute;
+
+#[Attribute(Attribute::TARGET_METHOD | Attribute::TARGET_FUNCTION)]
+class MyAttribute
+{
+}
+]]>
+    </programlisting>
+
+    <para>
+     在另一个类型中声明 <classname>MyAttribute</classname> 会在调用
+     <function>ReflectionAttribute::newInstance</function> 时抛出异常。
+    </para>
+   </example>
+
+   <para>
+    注解在每个声明中默认情况下只能使用一次。
+    如果需要重复,可以在 <literal>#[Attribute]</literal> 声明中设置字节位掩码。
+   </para>
+
+   <example>
+    <title>使用 IS_REPEATABLE 允许注解在声明中出现多次</title>
+
+    <programlisting role="php">
+<![CDATA[
+<?php
+
+namespace Example;
+
+use Attribute;
+
+#[Attribute(Attribute::TARGET_METHOD | Attribute::TARGET_FUNCTION | Attribute::IS_REPEATABLE)]
+class MyAttribute
+{
+}
+]]>
+    </programlisting>
+
+   </example>
+  </sect1>
+ </chapter>
+
+<!-- Keep this comment at the end of the file
+Local variables:
+mode: sgml
+sgml-omittag:t
+sgml-shorttag:t
+sgml-minimize-attributes:nil
+sgml-always-quote-attributes:t
+sgml-indent-step:1
+sgml-indent-data:t
+indent-tabs-mode:nil
+sgml-parent-document:nil
+sgml-default-dtd-file:"~/.phpdoc/manual.ced"
+sgml-exposed-tags:nil
+sgml-local-catalogs:nil
+sgml-local-ecat-files:nil
+End:
+vim600: syn=xml fen fdm=syntax fdl=2 si
+vim: et tw=78 syn=sgml
+vi: ts=1 sw=1
+-->