svn: /phpdoc/zh/trunk/language/oop5/ decon.xml

[email protected] (Dai Jie) Sat, 28 Nov 2020 08:08:43 +0000
Newsgroups php.doc.zh
Message-ID <[email protected]>
daijie                                   Sat, 28 Nov 2020 08:08:43 +0000

Revision: http://svn.php.net/viewvc?view=revision&revision=351721

Log:
Translate decon.xml

Changed paths:
    U   phpdoc/zh/trunk/language/oop5/decon.xml
svn-diffs-351721.txt (text/x-diff, 10.8 KB)
Modified: phpdoc/zh/trunk/language/oop5/decon.xml
===================================================================
--- phpdoc/zh/trunk/language/oop5/decon.xml	2020-11-28 08:07:24 UTC (rev 351720)
+++ phpdoc/zh/trunk/language/oop5/decon.xml	2020-11-28 08:08:43 UTC (rev 351721)
@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!-- $Revision$ -->
 <!-- $Author$ -->
-<!-- EN-Revision: 329168 Maintainer: lm92 Status: ready -->
+<!-- EN-Revision: 351474 Maintainer: lm92 Status: ready -->
 <sect1 xml:id="language.oop5.decon" xmlns="http://docbook.org/ns/docbook">
  <title>构造函数和析构函数</title>

@@ -9,11 +9,10 @@
   <title>构造函数</title>
    <methodsynopsis xml:id="object.construct">
     <type>void</type><methodname>__construct</methodname>
-    <methodparam choice="opt"><type>mixed</type><parameter>args</parameter></methodparam>
-    <methodparam choice="opt"><parameter>...</parameter></methodparam>
+    <methodparam rep="repeat"><type>mixed</type><parameter>values</parameter><initializer>""</initializer></methodparam>
    </methodsynopsis>
   <para>
-   PHP 5 允行开发者在一个类中定义一个方法作为构造函数。具有构造函数的类会在每次创建新对象时先调用此方法,所以非常适合在使用对象之前做一些初始化工作。
+   PHP 允许开发者在一个类中定义一个方法作为构造函数。具有构造函数的类会在每次创建新对象时先调用此方法,所以非常适合在使用对象之前做一些初始化工作。
   </para>
   <note>
    <simpara>
@@ -23,25 +22,25 @@
    </simpara>
   </note>
   <example>
-   <title>使用新标准的构造函数</title>
+   <title>继承中的构造函数</title>
    <programlisting role="php">
 <![CDATA[
 <?php
 class BaseClass {
-   function __construct() {
-       print "In BaseClass constructor\n";
-   }
+    function __construct() {
+        print "In BaseClass constructor\n";
+    }
 }

 class SubClass extends BaseClass {
-   function __construct() {
-       parent::__construct();
-       print "In SubClass constructor\n";
-   }
+    function __construct() {
+        parent::__construct();
+        print "In SubClass constructor\n";
+    }
 }

 class OtherSubClass extends BaseClass {
-    // inherits BaseClass's constructor
+    // 继承 BaseClass 的构造函数
 }

 // In BaseClass constructor
@@ -58,34 +57,173 @@
    </programlisting>
   </example>
   <para>
-   为了实现向后兼容性,如果 PHP 5 在类中找不到 <link linkend="object.construct">__construct()</link>
-   函数并且也没有从父类继承一个的话,它就会尝试寻找旧式的构造函数,也就是和类同名的函数。因此唯一会产生兼容性问题的情况是:类中已有一个名为
-   <function>__construct</function> 的方法却被用于其它用途时。
-  </para>
-  <para>
    与其它方法不同,当 <link linkend="object.construct">__construct()</link>
    被与父类 <link linkend="object.construct">__construct()</link>
    具有不同参数的方法覆盖时,PHP 不会产生一个 <constant>E_STRICT</constant> 错误信息。
   </para>
   <para>
-   自 PHP 5.3.3 起,在命名空间中,与类名同名的方法不再作为构造函数。这一改变不影响不在命名空间中的类。
+   自 PHP 5.3.3 起,在命名空间中,与类名同名的方法不再作为构造函数。不使用命名空间中的类则不受影响。
+    构造函数是一个普通的方法,在对应对象实例化时自动被调用。
+    因此可以定义任何数量的参数,可以是必选、可以有类型、可以有默认值。
+    构造器的参数放在类名后的括号里调用。
   </para>
   <example>
-   <title>Constructors in namespaced classes</title>
-   <programlisting role="php">
+   <title>使用构造器参数</title>
+    <programlisting role="php">
 <![CDATA[
 <?php
-namespace Foo;
-class Bar {
-    public function Bar() {
-        // treated as constructor in PHP 5.3.0-5.3.2
-        // treated as regular method as of PHP 5.3.3
+class Point {
+    protected int $x;
+    protected int $y;
+
+    public function __construct(int $x, int $y = 0) {
+        $this->x = $x;
+        $this->y = $y;
     }
 }
+
+// 两个参数都传入
+$p1 = new Point(4, 5);
+// 仅传入必填的参数。 $y 会默认取值 0。
+$p2 = new Point(4);
+// 使用命名参数(PHP 8.0 起):
+$p3 = new Point(y: 5, x: 4);
 ?>
 ]]>
-   </programlisting>
+    </programlisting>
   </example>
+   <para>
+   如果一个类没有构造函数,以及构造函数的参数不是必填项时,括号就可以省略。
+   </para>
+   <sect3>
+    <title>旧式风格的构造器</title>
+    <para>
+     PHP 8.0.0 之前,全局命名空间内的类如果有一个同名的方法,则会解析为旧式风格的构造器。
+     虽然函数能被当作构造器,但该语法已被废弃,并会导致 <constant>E_DEPRECATED</constant> 错误。
+     如果 <link linkend="object.construct">__construct()</link> 和同名方法同时存在时,
+     会调用 <link linkend="object.construct">__construct()</link>。
+    </para>
+    <para>
+     以下两种情况时,与类同名的方法不再有特殊意义:命名空间中的类、PHP 8.0.0 起的任何类。
+    </para>
+    <para>新代码中要使用 <link linkend="object.construct">__construct()</link>。
+    </para>
+   </sect3>
+   <sect3 xml:id="language.oop5.decon.constructor.promotion">
+    <title>构造器属性提升</title>
+    <para>
+     PHP 8.0.0 起,构造器的参数也可以相应提升为类的属性。
+     构造器的参数赋值给类属性的行为很普遍,否则无法操作。
+     而构造器提升的功能则为这种场景提供了便利。
+     因此上面的例子可以用以下方式重写:
+    </para>
+    <example>
+     <title>使用构造器属性提升</title>
+     <programlisting role="php">
+<![CDATA[
+<?php
+class Point {
+    public function __construct(protected int $x, protected int $y = 0) {
+    }
+}
+]]>
+     </programlisting>
+    </example>
+    <para>
+     当构造器参数带访问控制(visibility modifier)时,PHP 会同时把它当作对象属性和构造器参数,
+     并赋值到属性。
+     构造器可以是空的,或者包含其他语句。
+     参数值赋值到相应属性后执行正文中额外的代码语句。
+    </para>
+    <para>
+     并非所有参数都需要提升。可以混合提升或不提升参数作为属性,也不需要按顺序。
+     提升后的参数不影响构造器内代码调用。
+    </para>
+    <note>
+     <para>
+     对象属性的类型不能为 <type>callable</type> 以避免为引擎带来混淆。
+     因此提升的参数也不能是 <type>callable</type>。
+     其他任意 <link linkend="language.types.declarations">类型声明</link> 是允许的。
+     </para>
+    </note>
+    <note>
+     <para>
+      <!-- This should be linked once attributes are documented. -->
+      放在构造器提升参数里的属性会同时复制为属性和参数。
+     </para>
+    </note>
+   </sect3>
+   <sect3 xml:id="language.oop5.decon.constructor.static">
+    <title>Static 创造方法</title>
+    <para>
+     在 PHP 中每个 class 只能有一个构造器。
+     然而有些情况下,需要用不同的输入实现不同的方式构造对象。
+     这种情况下推荐使用 static 方法包装构造。
+    </para>
+    <example>
+     <title>使用 static 创造方法</title>
+     <programlisting role="php">
+<![CDATA[
+<?php
+class Product {
+
+    private ?int $id;
+    private ?string $name;
+
+    private function __construct(?int $id = null, ?string $name = null) {
+        $this->id = $id;
+        $this->name = $name;
+    }
+
+    public static function fromBasicData(int $id, string $name): static {
+        $new = new static($id, $name);
+        return $new;
+    }
+
+    public static function fromJson(string $json): static {
+        $data = json_decode($json);
+        return new static($data['id'], $data['name']);
+    }
+
+    public static function fromXml(string $xml): static {
+        // 此处放置自己的代码逻辑
+        $data = convert_xml_to_array($xml);
+        $new = new static();
+        $new->id = $data['id'];
+        $new->name = $data['name'];
+        return $new;
+    }
+}
+
+$p1 = Product::fromBasicData(5, 'Widget');
+$p2 = Product::fromJson($some_json_string);
+$p3 = Product::fromXml($some_xml_string);
+]]>
+     </programlisting>
+    </example>
+    <para>
+     可以设置构造器为 private 或 protected,防止自行额外调用。
+     这时只有 static 方法可以实例化一个类。
+     由于它们位于同一个定义的 class 因此可以访问私有方法,也不需要在同一个对象实例中。
+     当然构造器不一定要设置为 private,是否合理取决于实际情况。
+    </para>
+    <para>
+     三个 static 方法展示了对象以不同方式的实例化方式。
+    </para>
+    <simplelist>
+     <member><code>fromBasicData()</code> takes the exact parameters that are needed, then creates the
+      object by calling the constructor and returning the result.</member>
+     <member><code>fromJson()</code> accepts a JSON string and does some pre-processing on it itself
+     to convert it into the format desired by the constructor. It then returns the new object.</member>
+     <member><code>fromXml()</code> accepts an XML string, preprocesses it, and then creates a bare
+     object.  The constructor is still called, but as all of the parameters are optional the method
+     skips them.  It then assigns values to the object properties directly before returning the result.</member>
+    </simplelist>
+    <para>
+    在以上三个例子中,<code>static</code> 关键词会被翻译成代码所在类的类名。
+     这个例子中是 <code>Product</code>。
+    </para>
+   </sect3>
  </sect2>

  <sect2 xml:id="language.oop5.decon.destructor">
@@ -100,24 +238,25 @@
   </para>
   <example>
    <title>析构函数示例</title>
-   <programlisting role="php">
+    <programlisting role="php">
 <![CDATA[
 <?php
-class MyDestructableClass {
-   function __construct() {
-       print "In constructor\n";
-       $this->name = "MyDestructableClass";
-   }

-   function __destruct() {
-       print "Destroying " . $this->name . "\n";
-   }
+class MyDestructableClass
+{
+    function __construct() {
+        print "In constructor\n";
+    }
+
+    function __destruct() {
+        print "Destroying " . __CLASS__ . "\n";
+    }
 }

 $obj = new MyDestructableClass();
-?>
+
 ]]>
-   </programlisting>
+    </programlisting>
   </example>
   <para>
    和构造函数一样,父类的析构函数不会被引擎暗中调用。要执行父类的析构函数,必须在子类的析构函数体中显式调用
@@ -163,3 +302,4 @@
 vim: et tw=78 syn=sgml
 vi: ts=1 sw=1
 -->
+