diff --git a/language/oop5/final.xml b/language/oop5/final.xml index 8c7b89e52..bd3f7715c 100644 --- a/language/oop5/final.xml +++ b/language/oop5/final.xml @@ -1,11 +1,11 @@ - - + + Final 关键字 - final 关键字通过在定义方法和常量之前加上 final 来防止被子类覆盖。 + final 关键字通过在定义方法、属性和常量之前加上 final 来防止被子类覆盖。 如果一个类被声明为 final,则不能被继承。 @@ -62,11 +62,27 @@ class ChildClass extends BaseClass { - - - PHP 8.1.0 起可用的 final 常量示例 - - + PHP 8.4.0 起可用的 final 属性示例 + + +]]> + + + + PHP 8.1.0 起可用的 final 常量示例 + + ]]> - - - + + - 属性和常量不能被定义为 final,只有类、方法、常量(PHP 8.1.0 起)才能被定义为 final。 + 从 PHP 8.0.0 起,除了构造函数之外,私有方法也不能声明为 final 。 - 从 PHP 8.0.0 起,除了构造函数之外,私有方法也不能声明为 final 。 + 声明为 private(set) 的属性是隐式的 final diff --git a/language/oop5/properties.xml b/language/oop5/properties.xml index 7cee729e7..becbb6031 100644 --- a/language/oop5/properties.xml +++ b/language/oop5/properties.xml @@ -1,6 +1,6 @@ - + 属性 @@ -181,6 +181,9 @@ Fatal error: Uncaught Error: Typed property Shape::$numberOfSides must not be ac 只读属性 自 PHP 8.1.0 起,可以使用 readonly 修饰符声明属性,防止初始化后修改属性。 + 在 PHP 8.4.0 之前,readonly 属性是隐式的私有设置,只能从同一类写入。 + 从 PHP 8.4.0 开始,readonly 属性是隐式的 protected(set), + 因此可以从子类设置。如果需要,可以显式覆盖。 只读属性示例 diff --git a/language/oop5/visibility.xml b/language/oop5/visibility.xml index 00809415c..c768811eb 100644 --- a/language/oop5/visibility.xml +++ b/language/oop5/visibility.xml @@ -1,6 +1,6 @@ - + 访问控制(可见性) @@ -16,7 +16,6 @@ 类属性可以定义为public, private 或者 protected。在没有任何访问控制关键字的情况下,属性声明为 public。 - 属性声明 @@ -73,7 +72,118 @@ $obj2->printHello(); // 输出 Public2、Protected2 和 Undefined ]]> - + + 不对称属性可见性 + + 从 PHP 8.4 开始,属性也可以设置不对称的可见性,读取(get) + 和写入(set)可以有不同的范围。 + 具体来说,可以单独指定set可见性,只要它不比默认可见性更宽。 + + + 不对称属性可见性 + +author = $author; // OK + $this->pubYear = $year; // Fatal Error + } +} + +$b = new Book('How to PHP', 'Peter H. Peterson', 2024); + +echo $b->title; // Works +echo $b->author; // Works +echo $b->pubYear; // Fatal Error + +$b->title = 'How not to PHP'; // Fatal Error +$b->author = 'Pedro H. Peterson'; // Fatal Error +$b->pubYear = 2023; // Fatal Error +?> +]]> + + + 关于不对称可见性有一些注意事项: + + + + 只有声明了类型的属性才能有单独的set可见性。 + + + + + set 可见性必须和 get 可见性相同或更严格。 + 也就是说,public protected(set)protected protected(set) + 是允许的,但是 protected public(set) 会导致语法错误。 + + + + + 如果一个属性是 public,那么主要可见性可能被省略。 + 也就是说,public private(set)private(set) + 会有相同的结果。 + + + + + 一个属性的 private(set) 可见性会自动变为 final, + 并且不能在子类中重新声明。 + + + + + 读取属性的引用遵循 set 可见性,而不是 get。 + 这是因为引用可能用于修改属性值。 + + + + + 同样,试图写入数组属性会涉及到内部的 getset 操作, + 因此会遵循 set 可见性,因为这总是更严格的。 + + + + + 当一个类继承另一个类时,子类可以重新定义任何不是 final 的属性。 + 这样做时,可以扩大主要可见性或 set 可见性,只要新的可见性和父类相同或更宽。 + 但是要注意,如果一个 private 属性被重写,它实际上并没有改变父类的属性, + 而是创建了一个具有不同内部名称的新属性。 + + + 不对称属性继承 + + +]]> + + + @@ -81,8 +191,7 @@ $obj2->printHello(); // 输出 Public2、Protected2 和 Undefined 类中的方法可以被定义为 public、private 或 protected。如果没有设置这些关键字,则该方法默认为 public。 - - + 方法声明 test(); // Bar::testPrivate // Foo::testPublic ?> ]]> - - - + + @@ -180,32 +288,31 @@ $myFoo->test(); // Bar::testPrivate PHP 7.1.0 开始,类的常量可以定义为 public、private 或 protected。如果没有设置这些关键字,则该常量默认为 public。 - - - PHP 7.1.0 中的常量声明 - + + PHP 7.1.0 中的常量声明 + foo(); // 将会输出:Public Protected Private /** - * Define MyClass2 - */ +* Define MyClass2 +*/ class MyClass2 extends MyClass { - // This is public - function foo2() - { - echo self::MY_PUBLIC; - echo self::MY_PROTECTED; - echo self::MY_PRIVATE; // 这行会产生一个致命错误 - } + // This is public + function foo2() + { + echo self::MY_PUBLIC; + echo self::MY_PROTECTED; + echo self::MY_PRIVATE; // 这行会产生一个致命错误 + } } $myclass2 = new MyClass2; @@ -234,9 +341,8 @@ echo MyClass2::MY_PUBLIC; // 这行可以正常执行 $myclass2->foo2(); // 将会输出:Public Protected,MY_PRIVATE 是私有常量,无法输出 ?> ]]> - - - + +