rfc:final_class_const

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Next revision
Previous revision
Last revisionBoth sides next revision
rfc:final_class_const [2021/04/23 08:35] – created kocsismaterfc:final_class_const [2021/06/14 07:48] nikic
Line 2: Line 2:
   * Date: 2021-04-23   * Date: 2021-04-23
   * Author: Máté Kocsis <kocsismate@php.net>   * Author: Máté Kocsis <kocsismate@php.net>
-  * Status: Under discussion+  * Status: Accepted
   * Implementation: https://github.com/php/php-src/pull/6878   * Implementation: https://github.com/php/php-src/pull/6878
 +  * Target Version: PHP 8.1
  
 ===== Introduction ===== ===== Introduction =====
  
-Currently, class constants are always overridable by any child classes. This causes a few smaller caveats:+Currently, class constants are always overridable by child classes. This causes a few smaller caveats:
  
 First of all, the engine can't optimize class constant references when late static binding is involved, so it has to pessimistically assume that ''FOO'' is overridden in case of ''static::FOO'' or ''$this::FOO'' invocations. First of all, the engine can't optimize class constant references when late static binding is involved, so it has to pessimistically assume that ''FOO'' is overridden in case of ''static::FOO'' or ''$this::FOO'' invocations.
  
-But more importantly, one cannot easily make sure whether an inherited class constant is overridable or not. For example +What'more important is that class constants are not guaranteed to stay constant. Even if the declaring class always references them by using ''self::'', doing so won't prevent a child class from changing their value or even their type, unless the parent is a final class. Although constants not being constants is usually considered only as a theoretical problem, being able to add a ''final'' modifier would make the intention explicit that child classes shouldn't try to override them (e.g. because the parent doesn't use late static binding)
-let's consider the following code:+ 
 +A related interesting fact is that interface constants are already ''final'':
  
 <code php> <code php>
-class Foo+interface I
 { {
-    public const X = "foo"; +    public const X = "i";
-     +
-    public function getX(): string +
-    { +
-        return self::X; +
-    }+
 } }
  
-class Bar extends Foo+class C implements I
 { {
     public const X = "bar";     public const X = "bar";
-     
-    public function getBar(): string 
-    { 
-        return self::X; 
-    } 
 } }
 +
 +// Fatal error: Cannot inherit previously-inherited or override constant X from interface I
 </code> </code>
  
-When overriding a class constantone has to make sure that the parent class references class constants in an LSB context. +This leads to weird inconsistency. By introducing an intermediate class, overriding still becomes possible: 
 + 
 +<code php> 
 +interface I 
 +
 +    public const X = "i"; 
 +
 + 
 +class C implements I 
 +
 +
 + 
 +class D extends C  
 +
 +    public const X = "d"; 
 +
 + 
 +// No error 
 +</code>
  
  
 ===== Proposal ===== ===== Proposal =====
  
-The final modifier can be added to class constants. Doing so prevents a constant to be overridden in a child class:+The final modifier can be added to class constants. Doing so prevents overriding of a constant:
  
 <code php> <code php>
Line 57: Line 69:
 </code> </code>
  
-Besides, interface constants would become overridable by default:+Besides, interface constants would become overridable by default, and the ''final'' modifier could be used to retain the original behavior.
  
 <code php> <code php>
Line 68: Line 80:
 class C implements I class C implements I
 { {
-    public const X = "c"; // Overriding I::X is not possible+    public const X = "c"; // Overriding I::X is possible
     public const Y = "c"; // Overriding I::Y is not possible     public const Y = "c"; // Overriding I::Y is not possible
 } }
Line 77: Line 89:
 ===== Reflection ===== ===== Reflection =====
  
-A ''ReflectionClassConstant::isFinal()''method is added in order to be able to retrieve if a constant is final.+A ''ReflectionClassConstant::isFinal()'' method is added in order to be able to retrieve if a constant is final.
  
 ===== Backward Incompatible Changes ===== ===== Backward Incompatible Changes =====
Line 85: Line 97:
 ===== Vote ===== ===== Vote =====
  
-Add support for final class constants? The vote requires 2/3 majority to be accepted.+Voting started on 2021-05-19 08:00 UTC and ends 2021-06-02 08:00 UTC. The vote requires 2/3 majority to be accepted. 
 + 
 +<doodle title="Add support for final class constants?" auth="kocsismate" voteType="single" closed="true"> 
 +   * Yes 
 +   * No 
 +</doodle>
  
  
  
rfc/final_class_const.txt · Last modified: 2021/07/06 20:52 by kocsismate