com doc/zh: sync to en: oop 相关新 特性: .editorconfig language/functions. xml language/oop5/basic.xml
[email protected] (Bole Chen) Tue, 26 Jan 2021 02:55:14 +0000
| Newsgroups | php.doc.zh |
|---|---|
| Message-ID | <[email protected]> |
Commit: 6b35592a90301c4fff2093118d9024f5c50db664 Author: Bole Chen <[email protected]> Tue, 26 Jan 2021 10:55:14 +0800 Parents: 3042047601cab525c8c4a06ba11def7da79bb973 Branches: master Link: http://git.php.net/?p=doc/zh.git;a=commitdiff;h=6b35592a90301c4fff2093118d9024f5c50db664 Log: sync to en: oop 相关新特性 Changed paths: A .editorconfig M language/functions.xml M language/oop5/basic.xml
diff_6b35592a90301c4fff2093118d9024f5c50db664.txt
(text/plain, 45.2 KB)
diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 00000000..ae8c5287
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,7 @@
+# EditorConfig is awesome: https://EditorConfig.org
+
+root = true
+
+[*.xml]
+indent_style = space
+indent_size = 1
diff --git a/language/functions.xml b/language/functions.xml
index 2cd3e8c4..990ff875 100644
--- a/language/functions.xml
+++ b/language/functions.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- $Revision$ -->
<!-- $Author$ -->
-<!-- EN-Revision: 574f492ae951e820d36bc6d9273f9da90ba46ef7 Maintainer: avenger Status: ready -->
+<!-- EN-Revision: 4f04bd50ed71039b89e2b9a5aba7e53e74cac4c6 Maintainer: avenger Status: ready -->
<!-- CREDITS: Gregory, dallas -->
<chapter xml:id="language.functions" xmlns="http://docbook.org/ns/docbook">
<title>函数</title>
@@ -30,8 +30,8 @@ function foo($arg_1, $arg_2, /* ..., */ $arg_n)
</para>
<simpara>
- 任何有效的 PHP 代码都有可能出现在函数内部,甚至包括其它函数和 <link
- linkend="language.oop5.basic.class">类</link>定义。
+ 任何有效的 PHP 代码都有可能出现在函数内部,甚至包括其它函数和
+ <link linkend="language.oop5.basic.class">类</link> 定义。
</simpara>
<para>
函数名和 PHP 中的其它标识符命名规则相同。有效的函数名以字母或下划线打头,后面跟字母,数字或下划线。可以用正则表达式表示为:
@@ -65,7 +65,7 @@ if ($makefoo) {
}
}
-/* 现在可以安全调用函数 foo()了,
+/* 现在可以安全调用函数 foo()
因为 $makefoo 值为真 */
if ($makefoo) foo();
@@ -80,12 +80,6 @@ function bar()
</programlisting>
</example>
</para>
-
-
-
-
-
-
<para>
<example>
<title>函数中的函数</title>
@@ -100,12 +94,12 @@ function foo()
}
}
-/* 现在还不能调用bar()函数,因为它还不存在 */
+/* 现在还不能调用 bar() 函数,因为它还不存在 */
foo();
-/* 现在可以调用bar()函数了,因为foo()函数
- 的执行使得bar()函数变为已定义的函数 */
+/* 现在可以调用 bar() 函数了,因为 foo() 函数
+ 的执行使得 bar() 函数变为已定义的函数 */
bar();
@@ -126,20 +120,12 @@ bar();
的 ASCII 函数名是大小写无关的,不过在调用函数的时候,使用其在定义时相同的形式是个好习惯。
</simpara>
</note>
-
-
-
-
<simpara>
PHP 的函数支持 <link linkend="functions.variable-arg-list">可变数量的参数</link> 和
<link linkend="functions.arguments.default">默认参数</link>。参见
<function>func_num_args</function>,<function>func_get_arg</function> 和 <function>func_get_args</function>。
</simpara>
-
-
-
-
<para>
在 PHP 中可以调用递归函数。
<example>
@@ -160,14 +146,13 @@ function recursion($a)
</example>
<note>
<simpara>
- 但是要避免递归函数/方法调用超过
- 100-200 层,因为可能会使堆栈崩溃从而使当前脚本终止。
+ 但是要避免递归函数/方法调用超过 100-200 层,因为可能会使堆栈崩溃从而使当前脚本终止。
无限递归可视为编程错误。
</simpara>
</note>
</para>
- </sect1>
+ </sect1>
<sect1 xml:id="functions.arguments">
<title>函数的参数</title>
@@ -175,10 +160,7 @@ function recursion($a)
<simpara>
通过参数列表可以传递信息到函数,即以逗号作为分隔符的表达式列表。参数是从左向右求值的。
</simpara>
-
-
-
-
+
<para>
PHP 支持按值传递参数(默认),<link
linkend="functions.arguments.by-reference">通过引用传递参数</link> 以及 <link
@@ -200,12 +182,11 @@ function takes_array($input)
</programlisting>
</example>
</para>
-
<para>
从 PHP 8.0.0 开始,函数参数列表可以包含一个尾部的逗号,这个逗号将被忽略。这在参数列表较长或包含较长的变量名的情况下特别有用,这样可以方便地垂直列出参数。
</para>
<example>
- <title>Function Argument List with trailing Comma</title>
+ <title>函数参数使用尾部逗号</title>
<programlisting role="php">
<![CDATA[
<?php
@@ -223,7 +204,28 @@ function takes_many_args(
]]>
</programlisting>
</example>
+ <para>
+ As of PHP 8.0.0, passing mandatory arguments after optional arguments
+ is deprecated. This can generally be resolved by dropping the default value.
+ One exception to this rule are arguments of the form
+ <code>Type $param = null</code>, where the &null; default makes the type implicitly
+ nullable. This usage remains allowed, though it is recommended to use an
+ explicit nullable type instead.
+ </para>
+ <example>
+ <title>Passing optional arguments after mandatory arguments</title>
+ <programlisting role="php">
+<![CDATA[
+<?php
+function foo($a = [], $b) {} // 之前
+function foo($a, $b) {} // 之后
+function bar(A $a = null, $b) {} // 同时可用
+function bar(?A $a, $b) {} // 官方推荐的写法
+?>
+]]>
+ </programlisting>
+ </example>
<sect2 xml:id="functions.arguments.by-reference">
<title>通过引用传递参数</title>
@@ -233,7 +235,7 @@ function takes_many_args(
</simpara>
<para>
如果想要函数的一个参数总是通过引用传递,可以在函数定义中该参数的前面加上符号 &:
- </para>
+ </para>
<para>
<example>
<title>用引用传递函数参数</title>
@@ -253,10 +255,6 @@ echo $str; // outputs 'This is a string, and something extra.'
</example>
</para>
</sect2>
-
-
-
-
<sect2 xml:id="functions.arguments.default">
<title>默认参数的值</title>
@@ -310,15 +308,12 @@ echo makecoffee(array("cappuccino", "lavazza"), "teapot");
</programlisting>
</example>
</para>
-
<simpara>
默认值必须是常量表达式,不能是诸如变量,类成员,或者函数调用等。
</simpara>
<para>
注意当使用默认参数时,任何默认参数必须放在任何非默认参数的右侧;否则,函数将不会按照预期的情况工作。考虑下面的代码片断:
</para>
-
-
<para>
<example>
<title>函数默认参数的不正确用法</title>
@@ -337,7 +332,7 @@ echo makeyogurt("raspberry"); // won't work as expected
&example.outputs;
<screen>
<![CDATA[
-Warning: Missing argument 2 in call to makeyogurt() in
+Warning: Missing argument 2 in call to makeyogurt() in
/usr/local/etc/httpd/htdocs/phptest/functest.html on line 41
Making a bowl of raspberry .
]]>
@@ -377,13 +372,9 @@ Making a bowl of acidophilus raspberry.
</note>
</sect2>
-
-
-
<sect2 xml:id="functions.variable-arg-list">
<title>可变数量的参数列表</title>
-
<simpara>
PHP 在用户自定义函数中支持可变数量的参数列表。由
<literal>...</literal> 语法实现。
@@ -399,16 +390,13 @@ Making a bowl of acidophilus raspberry.
</simpara>
</note>
- <para>
- 包含 <literal>...</literal>
- 的参数,会转换为指定参数变量的一个数组,见以下示例:
-
+ <para>
+ 包含 <literal>...</literal>
+ 的参数,会转换为指定参数变量的一个数组,见以下示例:
-
-
- <example>
- <title>使用 <literal>...</literal> 来访问变量参数</title>
- <programlisting role="php">
+ <example>
+ <title>使用 <literal>...</literal> 来访问变量参数</title>
+ <programlisting role="php">
<![CDATA[
<?php
function sum(...$numbers) {
@@ -422,24 +410,24 @@ function sum(...$numbers) {
echo sum(1, 2, 3, 4);
?>
]]>
- </programlisting>
- &example.outputs;
- <screen>
+ </programlisting>
+ &example.outputs;
+ <screen>
<![CDATA[
10
]]>
- </screen>
- </example>
- </para>
+ </screen>
+ </example>
+ </para>
- <para>
- 也可以使用 <literal>...</literal> 语法来传递 <type>array</type> 或
- <classname>Traversable</classname> 做为参数到函数中:
+ <para>
+ 也可以使用 <literal>...</literal> 语法来传递 <type>array</type> 或
+ <classname>Traversable</classname> 做为参数到函数中:
- <example>
- <title>使用 <literal>...</literal> 来传递参数</title>
- <programlisting role="php">
+ <example>
+ <title>使用 <literal>...</literal> 来传递参数</title>
+ <programlisting role="php">
<![CDATA[
<?php
function add($a, $b) {
@@ -452,16 +440,16 @@ $a = [1, 2];
echo add(...$a);
?>
]]>
- </programlisting>
- &example.outputs;
- <screen>
+ </programlisting>
+ &example.outputs;
+ <screen>
<![CDATA[
3
3
]]>
- </screen>
- </example>
- </para>
+ </screen>
+ </example>
+ </para>
<para>
你可以在
@@ -477,8 +465,8 @@ echo add(...$a);
<example>
- <title>输入提示的变量参数</title>
- <programlisting role="php">
+ <title>输入提示的变量参数</title>
+ <programlisting role="php">
<![CDATA[
<?php
function total_intervals($unit, DateInterval ...$intervals) {
@@ -497,23 +485,22 @@ echo total_intervals('d', $a, $b).' days';
echo total_intervals('d', null);
?>
]]>
- </programlisting>
- &example.outputs;
- <screen>
+ </programlisting>
+ &example.outputs;
+ <screen>
<![CDATA[
3 days
Catchable fatal error: Argument 2 passed to total_intervals() must be an instance of DateInterval, null given, called in - on line 14 and defined in - on line 2
]]>
- </screen>
- </example>
- </para>
+ </screen>
+ </example>
+ </para>
- <para>
+ <para>
最后,你还可以给参数传递
- <link linkend="functions.arguments.by-reference">引用变量</link>,通过在
+ <link linkend="functions.arguments.by-reference">引用变量</link>,通过在
<literal>...</literal> 前加上一个 (<literal>&</literal>) 符号来实现。
- </para>
-
+ </para>
<sect3 xml:id="functions.variable-arg-list.old">
<title>旧版本的 PHP</title>
@@ -555,8 +542,112 @@ echo sum(1, 2, 3, 4);
</sect3>
</sect2>
- </sect1>
+ <sect2 xml:id="functions.named-arguments">
+ <title>Named Arguments</title>
+
+ <para>
+ PHP 8.0.0 introduced named arguments as an extension of the existing
+ positional parameters. Named arguments allow passing arguments to a
+ function based on the parameter name, rather than the parameter position.
+ This makes the meaning of the argument self-documenting, makes the
+ arguments order-independent and allows skipping default values arbitrarily.
+ </para>
+
+ <para>
+ Named arguments are passed by prefixing the value with the parameter name
+ followed by a colon. Using reserved keywords as parameter names is allowed.
+ The parameter name must be an identifier, specifying dynamically
+ is not allowed.
+ </para>
+
+ <example>
+ <title>Named argument syntax</title>
+ <programlisting role="php">
+ <![CDATA[
+<?php
+myFunction(paramName: $value);
+array_foobar(array: $value);
+
+// NOT supported.
+function_name($variableStoringParamName: $value);
+?>
+]]>
+ </programlisting>
+ </example>
+
+ <example>
+ <title>Positional arguments versus named arguments</title>
+ <programlisting role="php">
+ <![CDATA[
+<?php
+// Using positional arguments:
+array_fill(0, 100, 50);
+
+// Using named arguments:
+array_fill(start_index: 0, count: 100, value: 50);
+?>
+]]>
+ </programlisting>
+ </example>
+
+ <para>
+ The order in which the named arguments are passed does not matter.
+ </para>
+
+ <example>
+ <title>Same example as above with a different order of parameters</title>
+ <programlisting role="php">
+ <![CDATA[
+<?php
+array_fill(value: 50, num: 100, start_index: 0);
+?>
+]]>
+ </programlisting>
+ </example>
+
+ <para>
+ Named arguments can be combined with positional arguments. In this case,
+ the named arguments must come after the positional arguments.
+ It is also possible to specify only some of the optional arguments of a
+ function, regardless of their order.
+ </para>
+
+ <example>
+ <title>Combining named arguments with positional arguments</title>
+ <programlisting role="php">
+ <![CDATA[
+<?php
+htmlspecialchars($string, double_encode: false);
+// Same as
+htmlspecialchars($string, ENT_COMPAT | ENT_HTML401, 'UTF-8', false);
+?>
+]]>
+ </programlisting>
+ </example>
+
+ <para>
+ Passing the same parameter multiple times results in an Error exception.
+ </para>
+
+ <example>
+ <title>Error exception when passing the same parameter multiple times</title>
+ <programlisting role="php">
+ <![CDATA[
+<?php
+function foo($param) { ... }
+
+foo(param: 1, param: 2);
+// Error: Named parameter $param overwrites previous argument
+foo(1, param: 2);
+// Error: Named parameter $param overwrites previous argument
+?>
+]]>
+ </programlisting>
+ </example>
+
+ </sect2>
+ </sect1>
<sect1 xml:id="functions.returning-values">
<title>返回值</title>
@@ -571,14 +662,10 @@ echo sum(1, 2, 3, 4);
<function>return</function>,则返回值为 &null;。
</para>
</note>
-
-
-
-
<sect2>
- <title>return 的使用</title>
- <para>
+ <title>return 的使用</title>
+ <para>
<example>
<title><function>return</function> 的使用</title>
<programlisting role="php">
@@ -591,17 +678,17 @@ function square($num)
echo square(4); // outputs '16'.
?>
]]>
- </programlisting>
+ </programlisting>
</example>
- </para>
+ </para>
- <para>
- 函数不能返回多个值,但可以通过返回一个数组来得到类似的效果。
- </para>
- <para>
- <example>
- <title>返回一个数组以得到多个返回值</title>
- <programlisting role="php">
+ <para>
+ 函数不能返回多个值,但可以通过返回一个数组来得到类似的效果。
+ </para>
+ <para>
+ <example>
+ <title>返回一个数组以得到多个返回值</title>
+ <programlisting role="php">
<![CDATA[
<?php
function small_numbers()
@@ -611,19 +698,16 @@ function small_numbers()
list ($zero, $one, $two) = small_numbers();
?>
]]>
- </programlisting>
+ </programlisting>
</example>
- </para>
- <para>
- 从函数返回一个引用,必须在函数声明和指派返回值给一个变量时都使用引用运算符 &:
- </para>
- <para>
-
-
-
- <example>
- <title>从函数返回一个引用</title>
- <programlisting role="php">
+ </para>
+ <para>
+ 从函数返回一个引用,必须在函数声明和指派返回值给一个变量时都使用引用运算符 &:
+ </para>
+ <para>
+ <example>
+ <title>从函数返回一个引用</title>
+ <programlisting role="php">
<![CDATA[
<?php
function &returns_reference()
@@ -634,15 +718,14 @@ function &returns_reference()
$newref =& returns_reference();
?>
]]>
- </programlisting>
+ </programlisting>
</example>
- </para>
- <simpara>
+ </para>
+ <simpara>
有关引用的更多信息, 请查看 <link linkend="language.references">引用的解释</link>。
</simpara>
- </sect2>
- </sect1>
-
+ </sect2>
+ </sect1>
<sect1 xml:id="functions.variable-functions">
<title>可变函数</title>
@@ -650,7 +733,7 @@ $newref =& returns_reference();
<para>
PHP 支持可变函数的概念。这意味着如果一个变量名后有圆括号,PHP
将寻找与变量的值同名的函数,并且尝试执行它。可变函数可以用来实现包括回调函数,函数表在内的一些用途。
- </para>
+ </para>
<para>
可变函数不能用于例如
<function>echo</function>,<function>print</function>,<function>unset</function>,<function>isset</function>,<function>empty</function>,<function>include</function>,<function>require</function>
@@ -666,7 +749,8 @@ function foo() {
echo "In foo()<br />\n";
}
-function bar($arg = '') {
+function bar($arg = '')
+{
echo "In bar(); argument was '$arg'.<br />\n";
}
@@ -712,14 +796,13 @@ class Foo
$foo = new Foo();
$funcname = "Variable";
-$foo->$funcname(); // This calls $foo->Variable()
+$foo->$funcname(); // This calls $foo->Variable()
?>
]]>
</programlisting>
</example>
</para>
-
<para>
当调用静态方法时,函数调用要比静态属性优先:
<example>
@@ -775,7 +858,7 @@ $func(); // prints "bar"
</example>
</para>
- <sect2 role="seealso">
+ <sect2 role="seealso">
&reftitle.seealso;
<para>
<simplelist>
@@ -789,38 +872,37 @@ $func(); // prints "bar"
</sect1>
<sect1 xml:id="functions.internal">
- <title>内部(内置)函数</title>
-
- <para>
- PHP 有很多标准的函数和结构。还有一些函数需要和特定地 PHP
- 扩展模块一起编译,否则在使用它们的时候就会得到一个致命的“未定义函数”错误。例如,要使用
- <link linkend="ref.image">image</link> 函数中的
- <function>imagecreatetruecolor</function>,需要在编译 PHP 的时候加上
- <productname>GD</productname> 的支持。或者,要使用
- <function>mysqli_connect</function> 函数,就需要在编译 PHP 的时候加上
- <link linkend="book.mysqli">MySQLi</link> 支持。有很多核心函数已包含在每个版本的
- PHP 中如<link linkend="ref.strings">字符串</link>和<link
- linkend="ref.var">变量</link>函数。调用
- <function>phpinfo</function> 或者 <function>get_loaded_extensions</function>
- 可以得知 PHP 加载了那些扩展库。同时还应该注意,很多扩展库默认就是有效的。PHP
- 手册按照不同的扩展库组织了它们的文档。请参阅<link
- linkend="configuration">配置</link>,<link
- linkend="install">安装</link>以及各自的扩展库章节以获取有关如何设置 PHP 的信息。
- </para>
- <para>
- 手册中<link
- linkend="about.prototypes">如何阅读函数原型</link>讲解了如何阅读和理解一个函数的原型。确认一个函数将返回什么,或者函数是否直接作用于传递的参数是很重要的。例如,<function>str_replace</function>
- 函数将返回修改过的字符串,而 <function>usort</function>
- 却直接作用于传递的参数变量本身。手册中,每一个函数的页面中都有关于函数参数、行为改变、成功与否的返回值以及使用条件等信息。了解这些重要的(常常是细微的)差别是编写正确的
- PHP 代码的关键。
- </para>
+ <title>内部(内置)函数</title>
+
+ <para>
+ PHP 有很多标准的函数和结构。还有一些函数需要和特定地 PHP
+ 扩展模块一起编译,否则在使用它们的时候就会得到一个致命的“未定义函数”错误。例如,要使用
+ <link linkend="ref.image">image</link> 函数中的
+ <function>imagecreatetruecolor</function>,需要在编译 PHP 的时候加上
+ <productname>GD</productname> 的支持。或者,要使用
+ <function>mysqli_connect</function> 函数,就需要在编译 PHP 的时候加上
+ <link linkend="book.mysqli">MySQLi</link> 支持。有很多核心函数已包含在每个版本的
+ PHP 中如<link linkend="ref.strings">字符串</link>和<link
+ linkend="ref.var">变量</link>函数。调用
+ <function>phpinfo</function> 或者 <function>get_loaded_extensions</function>
+ 可以得知 PHP 加载了那些扩展库。同时还应该注意,很多扩展库默认就是有效的。PHP
+ 手册按照不同的扩展库组织了它们的文档。请参阅<link linkend="configuration">配置</link>,<link
+ linkend="install">安装</link>以及各自的扩展库章节以获取有关如何设置 PHP 的信息。
+ </para>
+ <para>
+ 手册中<link
+ linkend="about.prototypes">如何阅读函数原型</link>讲解了如何阅读和理解一个函数的原型。确认一个函数将返回什么,或者函数是否直接作用于传递的参数是很重要的。例如,<function>str_replace</function>
+ 函数将返回修改过的字符串,而 <function>usort</function>
+ 却直接作用于传递的参数变量本身。手册中,每一个函数的页面中都有关于函数参数、行为改变、成功与否的返回值以及使用条件等信息。了解这些重要的(常常是细微的)差别是编写正确的
+ PHP 代码的关键。
+ </para>
<note>
<simpara>
如果传递给函数的参数类型与实际的类型不一致,例如将一个 <type>array</type>
传递给一个 <type>string</type> 类型的变量,那么函数的返回值是不确定的。在这种情况下,通常函数会返回
&null;。但这仅仅是一个惯例,并不一定如此。
</simpara>
- </note>
+ </note>
<sect2 role="seealso">
&reftitle.seealso;
@@ -833,9 +915,8 @@ $func(); // prints "bar"
</simplelist>
</para>
</sect2>
- </sect1>
+ </sect1>
-
<sect1 xml:id="functions.anonymous">
<title>匿名函数</title>
@@ -843,7 +924,6 @@ $func(); // prints "bar"
匿名函数(Anonymous functions),也叫闭包函数(<literal>closures</literal>),允许
临时创建一个没有指定名称的函数。最经常用作回调函数 <type>callable</type>参数的值。当然,也有其它应用的情况。
</simpara>
-
<simpara>
匿名函数目前是通过 <link linkend="class.closure">
<classname>Closure</classname></link> 类来实现的。
@@ -885,10 +965,10 @@ $greet('PHP');
]]>
</programlisting>
</example>
-
+
<simpara>
闭包可以从父作用域中继承变量。
- 任何此类变量都应该用 <literal>use</literal> 语言结构传递进去。
+ 任何此类变量都应该用 <literal>use</literal> 语言结构传递进去。
PHP 7.1 起,不能传入此类变量: &link.superglobals;、 <varname>$this</varname> 或者和参数重名。
</simpara>
@@ -903,18 +983,18 @@ $message = 'hello';
$example = function () {
var_dump($message);
};
-echo $example();
+$example();
// 继承 $message
$example = function () use ($message) {
var_dump($message);
};
-echo $example();
+$example();
// Inherited variable's value is from when the function
// is defined, not when called
$message = 'world';
-echo $example();
+$example();
// Reset message
$message = 'hello';
@@ -923,12 +1003,12 @@ $message = 'hello';
$example = function () use (&$message) {
var_dump($message);
};
-echo $example();
+$example();
// The changed value in the parent scope
// is reflected inside the function call
$message = 'world';
-echo $example();
+$example();
// Closures can also accept regular arguments
$example = function ($arg) use ($message) {
@@ -955,10 +1035,9 @@ string(11) "hello world"
<para>
从 PHP 8.0.0 开始,作用域继承的变量列表可能包含一个尾部的逗号,这个逗号将被忽略。
</para>
-
<simpara>
这些变量都必须在函数或类的头部声明。
-
+
从父作用域中继承变量与使用全局变量是<emphasis>不同</emphasis>的。全局变量存在于一个全局的范围,无论当前在执行的是哪个函数。而
闭包的父作用域是定义该闭包的函数(不一定是调用它的函数)。示例如下:
</simpara>
@@ -977,23 +1056,23 @@ class Cart
const PRICE_MILK = 3.00;
const PRICE_EGGS = 6.95;
- protected $products = array();
-
+ protected $products = array();
+
public function add($product, $quantity)
{
$this->products[$product] = $quantity;
}
-
+
public function getQuantity($product)
{
return isset($this->products[$product]) ? $this->products[$product] :
FALSE;
}
-
+
public function getTotal($tax)
{
$total = 0.00;
-
+
$callback =
function ($quantity, $product) use ($tax, &$total)
{
@@ -1001,9 +1080,9 @@ class Cart
strtoupper($product));
$total += ($pricePerItem * $quantity) * ($tax + 1.0);
};
-
+
array_walk($this->products, $callback);
- return round($total, 2);;
+ return round($total, 2);
}
}
@@ -1021,8 +1100,7 @@ print $my_cart->getTotal(0.05) . "\n";
]]>
</programlisting>
</example>
-
-
+
<example>
<title>自动绑定 <literal>$this</literal></title>
<programlisting role="php">
@@ -1042,7 +1120,7 @@ class Test
$object = new Test;
$function = $object->testing();
$function();
-
+
?>
]]>
</programlisting>
@@ -1054,13 +1132,14 @@ object(Test)#1 (0) {
]]>
</screen>
</example>
-
+
<para>
当在类的上下文中声明时,当前的类会自动与之绑定,使得
<literal>$this</literal> 在函数的作用域中可用。如果不需要当前类的自动绑定,可以使用
<link linkend="functions.anonymous-functions.static">静态匿名函数</link> 替代。
</para>
- <sect2 xml:id="functions.anonymous-functions.static">
+
+ <sect2 xml:id="functions.anonymous-functions.static">
<title>静态匿名函数</title>
<para>
匿名函数允许被定义为静态化。这样可以防止当前类自动绑定到它们身上,对象在运行时也可能不会被绑定到它们上面。
@@ -1122,7 +1201,7 @@ Warning: Cannot bind an instance to a static closure in %s on line %d
</example>
</para>
</sect2>
-
+
<sect2 role="changelog">
&reftitle.changelog;
<para>
@@ -1161,7 +1240,6 @@ Warning: Cannot bind an instance to a static closure in %s on line %d
</sect2>
</sect1>
-
<sect1 xml:id="functions.arrow">
<title>箭头函数</title>
@@ -1197,7 +1275,7 @@ Warning: Cannot bind an instance to a static closure in %s on line %d
<?php
$y = 1;
-
+
$fn1 = fn($x) => $x + $y;
// 相当于 using $y by value:
$fn2 = function ($x) use ($y) {
@@ -1279,7 +1357,7 @@ var_export($x); // 输出 1
</programlisting>
</example>
</para>
-
+
<sect2 role="changelog">
&reftitle.changelog;
<para>
@@ -1336,4 +1414,3 @@ vim600: syn=xml fen fdm=syntax fdl=2 si
vim: et tw=78 syn=sgml
vi: ts=1 sw=1
-->
-
diff --git a/language/oop5/basic.xml b/language/oop5/basic.xml
index 7ec735ce..c02eca95 100755
--- a/language/oop5/basic.xml
+++ b/language/oop5/basic.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- $Revision$ -->
<!-- $Author$ -->
-<!-- EN-Revision: 0fe00e3574f5267948a29692e8daddaaeb275cee Maintainer: dallas Status: ready -->
+<!-- EN-Revision: 02f3bf57175c48abff767ad2c0961c6cfe58a39e Maintainer: avenger Status: ready -->
<sect1 xml:id="language.oop5.basic" xmlns="http://docbook.org/ns/docbook">
<title>基本概念</title>
@@ -13,10 +13,12 @@
</para>
<para>
类名可以是任何非 PHP
- <link linkend="reserved">保留字</link>的合法标签。一个合法类名以字母或下划线开头,后面跟着若干字母,数字或下划线。以正则表达式表示为:<literal>[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*</literal>。
+ <link linkend="reserved">保留字</link>
+ 的合法标签。一个合法类名以字母或下划线开头,后面跟着若干字母,数字或下划线。以正则表达式表示为:
+ <code>^[a-zA-Z_\x80-\xff][a-zA-Z0-9_\x80-\xff]*$</code>。
</para>
<para>
- 一个类可以包含有属于自己的<link
+ 一个类可以包含有属于自己的 <link
linkend="language.oop5.constants">常量</link>,<link
linkend="language.oop5.properties">变量</link>(称为“属性”)以及函数(称为“方法”)。
</para>
@@ -42,17 +44,17 @@ class SimpleClass
<para>
当一个方法在类定义内部被调用时,有一个可用的伪变量
<varname>$this</varname>。<varname>$this</varname>
- 是一个到主叫对象的引用(通常是该方法所从属的对象,但如果是从第二个对象<link
- linkend="language.oop5.static">静态</link>调用时也可能是另一个对象)。
+ 是一个到当前对象的引用。
</para>
- <para>
+ <warning>
+ <para>
+ 以静态方式去调用一个静态方法,将会抛出一个
+ <classname>Error</classname>。
+ 在 PHP 8.0.0 之前版本中,将会产生一个废弃通知,同时
+ <varname>$this</varname> 将会被声明为未定义。
+ </para>
<example xml:id="language.oop5.basic.class.this">
- <title><varname>$this</varname> 伪变量的示例</title>
- <simpara>
- We're assuming that error_reporting is disabled for this example;
- otherwise the following code would trigger deprecated and strict notices,
- respectively, depending on the PHP version.
- </simpara>
+ <title>使用 <varname>$this</varname> 伪变量的示例</title>
<programlisting role="php">
<![CDATA[
<?php
@@ -89,40 +91,58 @@ $b->bar();
B::bar();
?>
]]>
- </programlisting>
- &example.outputs.5;
+ </programlisting>
+ &example.outputs.7;
<screen>
<![CDATA[
$this is defined (A)
+
+Deprecated: Non-static method A::foo() should not be called statically in %s on line 27
+$this is not defined.
+
+Deprecated: Non-static method A::foo() should not be called statically in %s on line 20
$this is not defined.
-$this is defined (B)
+
+Deprecated: Non-static method B::bar() should not be called statically in %s on line 32
+
+Deprecated: Non-static method A::foo() should not be called statically in %s on line 20
$this is not defined.
]]>
</screen>
- &example.outputs.7;
+ &example.outputs.8;
<screen>
<![CDATA[
$this is defined (A)
-$this is not defined.
-$this is not defined.
-$this is not defined.
+
+Fatal error: Uncaught Error: Non-static method A::foo() cannot be called statically in %s :27
+Stack trace:
+#0 {main}
+ thrown in %s on line 27
]]>
</screen>
- </example>
- </para>
- </sect2>
+ </example>
+ </warning>
+ </sect2>
<sect2 xml:id="language.oop5.basic.new">
<title>new</title>
<para>
要创建一个类的实例,必须使用 <literal>new</literal>
- 关键字。当创建新对象时该对象总是被赋值,除非该对象定义了<link
- linkend="language.oop5.decon">构造函数</link>并且在出错时抛出了一个<link
+ 关键字。当创建新对象时该对象总是被赋值,除非该对象定义了 <link
+ linkend="language.oop5.decon">构造函数</link> 并且在出错时抛出了一个 <link
linkend="language.exceptions">异常</link>。类应在被实例化之前定义(某些情况下则必须这样)。
</para>
<para>
- 如果在 <literal>new</literal> 之后跟着的是一个包含有类名的字符串 <type>string</type>,则该类的一个实例被创建。如果该类属于一个命名空间,则必须使用其完整名称。
+ 如果在 <literal>new</literal> 之后跟着的是一个包含有类名的字符串
+ <type>string</type>,则该类的一个实例被创建。如果该类属于一个命名空间,则必须使用其完整名称。
</para>
+
+ <note>
+ <para>
+ 如果没有参数要传递给类的构造函数,类名后的括号则可以省略掉。
+ </para>
+ </note>
+
<example>
<title>创建实例</title>
<programlisting role="php">
@@ -131,8 +151,8 @@ $this is not defined.
$instance = new SimpleClass();
// 也可以这样做:
-$className = 'Foo';
-$instance = new $className(); // Foo()
+$className = 'SimpleClass';
+$instance = new $className(); // new SimpleClass()
?>
]]>
</programlisting>
@@ -141,8 +161,8 @@ $instance = new $className(); // Foo()
在类定义内部,可以用 <literal>new self</literal> 和 <literal>new parent</literal> 创建新对象。
</para>
<para>
- 当把一个对象已经创建的实例赋给一个新变量时,新变量会访问同一个实例,就和用该对象赋值一样。此行为和给函数传递入实例时一样。可以用<link
- linkend="language.oop5.cloning">克隆</link>给一个已创建的对象建立一个新实例。
+ 当把一个对象已经创建的实例赋给一个新变量时,新变量会访问同一个实例,就和用该对象赋值一样。此行为和给函数传递入实例时一样。可以用
+ <link linkend="language.oop5.cloning">克隆</link> 给一个已创建的对象建立一个新实例。
</para>
<example>
<title>对象赋值</title>
@@ -178,7 +198,7 @@ object(SimpleClass)#1 (1) {
</screen>
</example>
<para>
- PHP 5.3.0 引进了两个新方法来创建一个对象的实例:
+ 有几种方法可以创建一个对象的实例。
</para>
<example>
<title>创建新对象</title>
@@ -207,19 +227,19 @@ $obj4 = Child::getNew();
var_dump($obj4 instanceof Child);
?>
]]>
- </programlisting>
- &example.outputs;
- <screen>
+ </programlisting>
+ &example.outputs;
+ <screen>
<![CDATA[
bool(true)
bool(true)
bool(true)
]]>
- </screen>
- </example>
-
+ </screen>
+ </example>
+
<para>
- PHP 5.4.0 起,可以通过一个表达式来访问新创建对象的成员:
+ 可以通过一个表达式来访问新创建对象的成员:
</para>
<example>
<title>访问新创建对象的成员</title>
@@ -237,26 +257,28 @@ echo (new DateTime())->format('Y');
]]>
</screen>
</example>
- </sect2>
-
+
+ <note>
+ <simpara>
+ 在 PHP 7.1 之前,如果类没有定义构造函数,则不对参数进行执行。
+ </simpara>
+ </note>
+ </sect2>
+
<sect2 xml:id="language.oop5.basic.properties-methods">
- <title>Properties and methods</title>
+ <title>属性和方法</title>
<para>
- Class properties and methods live in separate "namespaces", so it is
- possible to have a property and a method with the same name. Referring to
- both a property and a method has the same notation, and whether a property
- will be accessed or a method will be called, solely depends on the context,
- i.e. whether the usage is a variable access or a function call.
+ 类的属性和方法存在于不同的“命名空间”中,这意味着同一个类的属性和方法可以使用同样的名字。在类中访问属性和调用方法使用同样的操作符,具体是访问一个属性还是调用一个方法,取决于你的上下文,即用法是变量访问还是函数调用。
</para>
<example>
- <title>Property access vs. method call</title>
+ <title>访问类属性 vs. 调用类方法</title>
<programlisting role="php">
<![CDATA[
<?php
class Foo
{
public $bar = 'property';
-
+
public function bar() {
return 'method';
}
@@ -275,21 +297,19 @@ method
</screen>
</example>
<para>
- That means that calling an <link linkend="functions.anonymous">anonymous
- function</link> which has been assigned to a property is not directly
- possible. Instead the property has to be assigned to a variable first, for
- instance. As of PHP 7.0.0 it is possible to call such a property directly
- by enclosing it in parentheses.
+ 这意味着,如果你的类属性被分配给一个
+ <link linkend="functions.anonymous">匿名函数</link>
+ 你将无法直接调用它。因为访问类属性的优先级要更高,在此场景下需要用括号包裹起来调用。
</para>
<example>
- <title>Calling an anonymous function stored in a property</title>
+ <title>类属性被赋值为匿名函数时的调用示例</title>
<programlisting role="php">
<![CDATA[
<?php
class Foo
{
public $bar;
-
+
public function __construct() {
$this->bar = function() {
return 42;
@@ -299,11 +319,6 @@ class Foo
$obj = new Foo();
-// as of PHP 5.3.0:
-$func = $obj->bar;
-echo $func(), PHP_EOL;
-
-// alternatively, as of PHP 7.0.0:
echo ($obj->bar)(), PHP_EOL;
]]>
</programlisting>
@@ -317,10 +332,12 @@ echo ($obj->bar)(), PHP_EOL;
</sect2>
<sect2 xml:id="language.oop5.basic.extends">
+ <!-- TODO Example about class constant redefinition -->
+ <!-- TODO Split into it's own page? -->
<title>extends</title>
<para>
一个类可以在声明中用 <literal>extends</literal>
- 关键字继承另一个类的方法和属性。PHP不支持多重继承,一个类只能继承一个基类。
+ 关键字继承另一个类的方法和属性。PHP 不支持多重继承,一个类只能继承一个基类。
</para>
<para>
被继承的方法和属性可以通过用同样的名字重新声明被覆盖。但是如果父类定义方法时使用了
@@ -328,10 +345,6 @@ echo ($obj->bar)(), PHP_EOL;
<link linkend="language.oop5.paamayim-nekudotayim">parent::</link>
来访问被覆盖的方法或属性。
</para>
- <para>
- 当覆盖方法时,参数必须保持一致否则 PHP 将发出 <constant>E_STRICT</constant>
- 级别的错误信息。但构造函数例外,构造函数可在被覆盖时使用不同的参数。
- </para>
<example>
<title>简单的类继承</title>
<programlisting role="php">
@@ -339,7 +352,7 @@ echo ($obj->bar)(), PHP_EOL;
<?php
class ExtendClass extends SimpleClass
{
- // Redefine the parent method
+ // 同样名称的方法,将会覆盖父类的方法
function displayVar()
{
echo "Extending class\n";
@@ -360,13 +373,176 @@ a default value
]]>
</screen>
</example>
- </sect2>
-
+
+ <sect3 xml:id="language.oop.lsp">
+ <title>Signature compatibility rules</title>
+ <para>
+ When overriding a method, its signature must be compatible with the parent
+ method. Otherwise, a fatal error is emitted, or, prior to PHP 8.0.0, an
+ <constant>E_WARNING</constant> level error is generated.
+ A signature is compatible if it respects the
+ <link linkend="language.oop5.variance">variance</link> rules, makes a
+ mandatory parameter optional, and if any new parameters are optional.
+ This is known as the Liskov Substitution Principle, or LSP for short.
+ The <link linkend="language.oop5.decon.constructor">constructor</link>,
+ and <literal>private</literal> methods are exempt from these signature
+ compatibility rules, and thus won't emit a fatal error in case of a
+ signature mismatch.
+ </para>
+ <example>
+ <title>Compatible child methods</title>
+ <programlisting role="php">
+<![CDATA[
+<?php
+
+class Base
+{
+ public function foo(int $a) {
+ echo "Valid\n";
+ }
+}
+
+class Extend1 extends Base
+{
+ function foo(int $a = 5)
+ {
+ parent::foo($a);
+ }
+}
+
+class Extend2 extends Base
+{
+ function foo(int $a, $b = 5)
+ {
+ parent::foo($a);
+ }
+}
+
+$extended1 = new Extend1();
+$extended1->foo();
+$extended2 = new Extend2();
+$extended2->foo(1);
+]]>
+ </programlisting>
+ &example.outputs;
+ <screen>
+<![CDATA[
+Valid
+Valid
+]]>
+ </screen>
+ </example>
+
+ <para>
+ The following examples demonstrate that a child method which removes a parameter, or makes an optional
+ parameter mandatory, is not compatible with the parent method.
+ </para>
+ <example>
+ <title>Fatal error when a child method removes a parameter</title>
+ <programlisting role="php">
+<![CDATA[
+<?php
+
+class Base
+{
+ public function foo(int $a = 5) {
+ echo "Valid\n";
+ }
+}
+
+class Extend extends Base
+{
+ function foo()
+ {
+ parent::foo(1);
+ }
+}
+]]>
+ </programlisting>
+ &example.outputs.8.similar;
+ <screen>
+<![CDATA[
+Fatal error: Declaration of Extend::foo() must be compatible with Base::foo(int $a = 5) in /in/evtlq on line 13
+]]>
+ </screen>
+ </example>
+ <example>
+ <title>Fatal error when a child method makes an optional parameter mandatory</title>
+ <programlisting role="php">
+<![CDATA[
+<?php
+
+class Base
+{
+ public function foo(int $a = 5) {
+ echo "Valid\n";
+ }
+}
+
+class Extend extends Base
+{
+ function foo(int $a)
+ {
+ parent::foo($a);
+ }
+}
+]]>
+ </programlisting>
+ &example.outputs.8.similar;
+ <screen>
+<![CDATA[
+Fatal error: Declaration of Extend::foo(int $a) must be compatible with Base::foo(int $a = 5) in /in/qJXVC on line 13
+]]>
+ </screen>
+ </example>
+
+ <warning>
+ <para>
+ Renaming a method's parameter in a child class is not a signature
+ incompatibility. However, this is discouraged as it will result in a
+ runtime <classname>Error</classname> if
+ <link linkend="functions.named-arguments">named arguments</link>
+ are used.
+ </para>
+ <example>
+ <title>Error when using named arguments and parameters were renamed in a child class</title>
+ <programlisting role="php">
+<![CDATA[
+<?php
+
+class A {
+ public function test($foo, $bar) {}
+}
+
+class B extends A {
+ public function test($a, $b) {}
+}
+
+$obj = new B;
+
+// Pass parameters according to A::test() contract
+$obj->test(foo: "foo", bar: "bar"); // ERROR!
+]]>
+ </programlisting>
+ &example.outputs.similar;
+ <screen>
+<![CDATA[
+Fatal error: Uncaught Error: Unknown named parameter $foo in /in/XaaeN:14
+Stack trace:
+#0 {main}
+ thrown in /in/XaaeN on line 14
+]]>
+ </screen>
+ </example>
+ </warning>
+ </sect3>
+ </sect2>
+
<sect2 xml:id="language.oop5.basic.class.class">
<title>::class</title>
-
+
<para>
- 自 PHP 5.5 起,关键词 <literal>class</literal> 也可用于类名的解析。使用 <literal>ClassName::class</literal> 你可以获取一个字符串,包含了类 <literal>ClassName</literal> 的完全限定名称。这对使用了
+ 关键词 <literal>class</literal> 也可用于类名的解析。使用 <literal>ClassName::class</literal> 你可以获取一个字符串,包含了类 <literal>ClassName</literal> 的完全限定名称。这对使用了
<link linkend="language.namespaces">命名空间</link> 的类尤其有用。
</para>
<para>
@@ -378,7 +554,7 @@ a default value
namespace NS {
class ClassName {
}
-
+
echo ClassName::class;
}
?>
@@ -393,14 +569,98 @@ NS\ClassName
</example>
</para>
<note>
- <para>The class name resolution using <literal>::class</literal> is a
- compile time transformation. That means at the time the class name string
- is created no autoloading has happened yet. As a consequence, class names
- are expanded even if the class does not exist. No error is issued in
- that case.
+ <para>使用 <literal>::class</literal>
+ 解析类名操作会在底层编译时进行。这意味着在执行该操作时,类还没有被加载。因此,即使要调用的类不存在,类名也会被展示。在此种场景下,并不会发生错误。
</para>
+ <example xml:id="language.oop5.basic.class.class.fail">
+ <title>解析不存在的类名</title>
+ <programlisting role="php">
+<![CDATA[
+<?php
+print Does\Not\Exist::class;
+?>
+]]>
+ </programlisting>
+ &example.outputs;
+ <screen>
+<![CDATA[
+Does\Not\Exist
+]]>
+ </screen>
+ </example>
</note>
+ <para>
+ 自 PHP 8.0.0 起,<literal>::class</literal> 关键字也可以对象上使用。与上述情况不同,此时解析将会在运行时进行。此操作的运行结果和
+ <function>get_class</function> 函数一致。
+ </para>
+ <example xml:id="language.oop5.basic.class.class.object">
+ <title>类名解析</title>
+ <programlisting role="php">
+<![CDATA[
+<?php
+namespace NS {
+ class ClassName {
+ }
+}
+$c = new ClassName();
+print $c::class;
+?>
+]]>
+ </programlisting>
+ &example.outputs;
+ <screen>
+<![CDATA[
+NS\ClassName
+]]>
+ </screen>
+ </example>
</sect2>
+ <sect2 xml:id="language.oop5.basic.nullsafe">
+ <title>Nullsafe 方法和属性</title>
+ <para>
+ 自 PHP 8.0.0 起,类属性和方法新增加了一个 "nullsafe" 操作符:
+ <literal>?-></literal>。The nullsafe operator
+ works the same as property or method access as above, except that if the
+ object being dereferenced is &null; then &null;
+ will be returned rather than an exception thrown. If the dereference is part of a
+ chain, the rest of the chain is skipped.
+ </para>
+ <para>
+ 此操作的结果,类似于在每次访问前使用 <function>is_null</function> 函数判断方法和属性是否存在,但更加简洁。
+ </para>
+ <para>
+ <example>
+ <title>Nullsafe 操作符</title>
+ <programlisting role="php">
+<![CDATA[
+<?php
+
+// 自 PHP 8.0.0 起可用
+$result = $repository?->getUser(5)?->name;
+
+// 上边那行代码等价于以下代码
+if (is_null($repository)) {
+ $result = null;
+} else {
+ $user = $repository->getUser(5);
+ if (is_null($user)) {
+ $result = null;
+ } else {
+ $result = $user->name;
+ }
+}
+?>
+]]>
+ </programlisting>
+ </example>
+ </para>
+ <note>
+ <para>
+ 仅当 null 被认为是属性或方法返回的有效和预期的可能值时,才推荐使用 nullsafe
+ 操作符。如果业务中需要明确指示错误,抛出异常会是更好的处理方式。
+ </para>
+ </note>
+ </sect2>
</sect1>
<!-- Keep this comment at the end of the file