rfc:short-and-inner-classes

Differences

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

Link to this comparison view

Both sides previous revisionPrevious revision
Next revision
Previous revision
rfc:short-and-inner-classes [2025/03/05 22:12] – updated copy withinboredomrfc:short-and-inner-classes [2025/03/15 10:28] (current) – reword and clarify withinboredom
Line 1: Line 1:
-====== PHP RFC: Inner Classes with Short Syntax ======+====== PHP RFC: Inner Classes ======
  
-  * Version: 0.1+  * Version: 0.4
   * Date: 2025-02-08   * Date: 2025-02-08
   * Author: Rob Landers, <rob@bottled.codes>   * Author: Rob Landers, <rob@bottled.codes>
-  * Status: Draft (or Under Discussion or Accepted or Declined)+  * Status: Under Discussion (Accepted or Declined)
   * First Published at: http://wiki.php.net/rfc/short-and-inner-classes   * First Published at: http://wiki.php.net/rfc/short-and-inner-classes
  
 ===== Introduction ===== ===== Introduction =====
  
-This RFC proposes two significant enhancements to the language: **Short Class Syntax** and **Inner Classes**. These features aim to streamline class definitions, reduce boilerplateand introduce a new level of encapsulation and organization within PHP applications.+This RFC proposes significant enhancement to the language: **Inner Classes**. Inner classes enable the definition of classes within other classesintroducing a new level of encapsulation and organization within PHP applications.
  
-Short Class Syntax allows developers to define simple or data-oriented classes in a single line, leveraging constructor property promotion to enhance readability and maintainabilityInner Classes, on the other hand, enable the definition of within other classes, providing fine-grained visibility control and fostering better modularization.+**Inner Classes** allows for the ability to define classes within other classes and control the use of inner classes through visibilityMany languages allow the encapsulation of behavior through inner classes (sometimes called **nested classes**), such as Java, C#, and many others.
  
-By adopting these enhancements, PHP can offer developers more powerful tools to write clean, efficient, and well-structured codeultimately improving the overall developer experience and code quality.+PHP developers currently rely heavily on annotations (e.g., @internal) or naming conventions to indicate encapsulation of Data Transfer Objects (DTOs) and related internal classes. These approaches offer limited enforcementcausing potential misuse or unintended coupling. 
 + 
 +This RFC introduces Inner Classes to clearly communicate and enforce boundaries around encapsulated classes, facilitating well-known design patterns (e.g., Builder, DTO, serialization patterns) with native language support. This reduces boilerplate, enhances clarity, and ensures internal types remain truly internal.
  
 ===== Proposal ===== ===== Proposal =====
  
-==== Short Class Syntax ==== +Inner classes allow defining classes within other classes, following standard visibility rules. This allows developers to declare a class as ''%%private%%'' or ''%%protected%%'' and restrict its usage to the outer class. They are accessed via new operator: ''%%:>%%'' which is a mixture of ''%%->%%'' and ''%%::%%''.
- +
-The proposed syntax for defining a short class consists of the class keyword, followed by the class name, and list of properties in parentheses. Optionally, traits, interfaces, and a parent class can be specified.+
  
 <code php> <code php>
 +class Outer {
 +    public class Inner {
 +        public function __construct(public string $message) {}
 +    }
 +    
 +    private class PrivateInner {
 +        public function __construct(public string $message) {}
 +    }
 +}
  
-// a simple class with two public properties +$foo = new Outer:>Inner('Hello, world!'); 
-class Point(int $xint $y);+echo $foo->message; 
 +// outputs: Hello, world! 
 +$baz = new Outer:>PrivateInner('Helloworld!'); 
 +// Fatal error: Class 'Outer:>PrivateInner' is private 
 +</code>
  
-// A readonly class with a parent class, interface, and traits +Inner classes are just regular class definitions with a couple additional features. That means, except where otherwise noted, "how would inner classes work in situation X?" can be answered with "the same as any other class/object." 
-readonly class Vector(int $x, private int $yextends BaseVector implements JsonSerializable use PointTraitEvolvable;+ 
 +==== Declaration Syntax ==== 
 + 
 +Declaring an inner class is just like declaring any other class. You can define ''%%readonly%%''''%%final%%'', and ''%%abstract%%'' inner classes -- or combinations, for example. However, when defining an inner class, you may also define it as ''%%private%%'', ''%%protected%%'', or ''%%public%%''. 
 + 
 +If an inner class does not explicitly declare visibility (private, protected, or public), it is implicitly considered public. This matches PHP’s existing class behavior for methods and properties. 
 + 
 +<code php> 
 +class Outer { 
 +    private class Inner {} 
 +    protected readonly class ReadOnlyInner {} 
 +    public abstract class AbstractInner {} 
 +    public final class FinalInner {} 
 +}
 </code> </code>
  
-This is equivalent to the following full class definition:+If an inner class is not defined as ''%%private%%'', ''%%protected%%'', or ''%%public%%'', it is assumed to be ''%%public%%''
 + 
 +==== Syntax rationale ==== 
 + 
 +The ''%%:>%%'' syntax was selected after evaluating alternatives: 
 + 
 +  * Using ''%%::%%'' was cumbersome and visually ambiguous due to existing static resolution syntax. 
 +  * Using ''%%\%%'' or ''%%\\%%'' was rejected due to potential conflicts with namespaces and escaping, causing confusion. 
 + 
 +''%%:>%%'' communicates "inner membership," visually linking the inner class to the outer class. 
 + 
 +==== Binding ==== 
 + 
 +Inner classes are explicitly bound to their outer classes and are intentionally not inherited through subclassing, traits, or interfaces. This prevents ambiguity or complexity arising from inheriting tightly bound encapsulated logic.
  
 <code php> <code php>
-class Point +class Outer 
-    public function __construct(public int $x, public int $y) {}+    class OuterInner {}
 } }
  
-readonly public class Vector extends BaseVector implements JsonSerializable +interface Foo { 
-    use PointTrait, Evolvable;+    class FooInner {} 
 +
 + 
 +trait Bar { 
 +    class BarInner {} 
 +
 + 
 +class All extends Outer implements Foo 
 +    use Bar;
          
-    public function __construct(public int $x, private int $y) {}+    public function does_not_work() { 
 +        new self:>OuterInner(); // Fatal error: Class 'All:>OuterInner' not found 
 +        new self:>FooInner(); // Fatal error: Class 'All:>FooInner' not found 
 +        new self:>BarInner(); // Fatal error: Class 'All:>BarInner' not found 
 +         
 +        new parent:>OuterInner(); // This does work because it resolves to Outer:>OuterInner 
 +    }
 } }
 </code> </code>
  
-Properties inside parentheses are automatically declared as class properties and default to public unless explicitly specified.+=== static resolution ===
  
-=== Default Values ===+The ''%%static%%'' keyword is **not** supported to resolve inner classes. Attempting to do so results in an error, depending on where it is used:
  
-Properties with type hints may have default values:+<code php> 
 +class Outer { 
 +    class Inner {} 
 +     
 +    // Fatal error: Cannot use the static modifier on a parameter 
 +    public function foo(static:>Inner $bar) {} 
 +     
 +    // Parse error: syntax error, unexpected token ":>", expecting ";" or "{" 
 +    public function bar(): static:>Inner {} 
 +     
 +    // Fatal error: Cannot use "static" as class name, as it is reserved  
 +    class Baz extends static:>Inner {} 
 +     
 +    public function foobar() { 
 +        return new static:>Inner(); // Fatal error: Cannot use the static modifier on an inner class 
 +    } 
 +
 +</code> 
 + 
 +This is to prevent casual LSP violations of inheritance and to maintain the strong binding of inner classes. 
 + 
 +=== parent resolution === 
 + 
 +The ''%%parent%%'' keyword is supported to resolve inner classes. Which parent it resolves to depends on the context:
  
 <code php> <code php>
-class Point(int $x = 0int $y = 0);+class Foo { 
 +    class Bar {} 
 +
 + 
 +class Baz extends Foo { 
 +    // parent:>Bar resolves to Foo:>Bar 
 +    class Bar extends parent:>Bar { 
 +        // inside the class bodyparent refers to Foo:>Bar 
 +        public function doSomething(): parent {}  
 +    } 
 +}
 </code> </code>
  
-=== Inheritance and Behavior ===+''%%parent%%'' explicitly resolves to the parent class of the current class body it is written in and helps with writing more concise code.
  
-Short classes can extend other classes, implement interfaces, and use traits, but they cannot define additional methods except by using traitsIf the parent class has a constructor, the constructor will be overridden and **not called**.+=== self resolution === 
 + 
 +The ''%%self%%'' keyword is supported to resolve inner classes. Which ''%%self%%'' it resolves to depends on the context:
  
 <code php> <code php>
-class Point(int $x, int $yextends BasePoint implements JsonSerializable use PointTrait, Evolvable;+class Outer { 
 +  class Middle { 
 +    class Other {} 
 +   
 +    // extends Outer:>Middle:>Other 
 +    class Inner extends self:>Other { 
 +        public function foo(): self {} // returns Outer:>Middle:>Inner 
 +    } 
 +  } 
 +}
 </code> </code>
  
-=== Empty Classes ===+''%%self%%'' explicitly resolves to the current class body it is written in, just like with ''%%parent%%''. On ''%%inner%%'' classes.
  
-Short classes may be empty, in which case, the constructor is not overridden. This can be useful in some casessuch as when you want to define a simple exception:+When using self inside a class body to refer to an inner classif the inner class is not found in the current classit will fail with an error.
  
 <code php> <code php>
-class HttpError() extends Exception;+class OuterParent { 
 +    class Inner {} 
 +    class Other {} 
 +}
  
-throw new HttpError('Not Found', 404);+class MiddleChild extends OuterParent { 
 +    // Fatal Error: cannot find class MiddleChild:>InnerParent 
 +    class Inner extends self:>InnerParent {} 
 +
 + 
 +class OuterChild extends OuterParent { 
 +    class Inner {} 
 +    public function foo() { 
 +        $inner = new self:>Inner(); // resolves to OuterChild:>Inner 
 +        $inner = new parent:>Inner(); // resolves to OuterParent:>Inner 
 +        $inner = new self:>Other(); // Fatal Error: cannot find class OuterChild:>Other 
 +        $inner = new parent:>Other(); // resolves to OuterParent:>Other 
 +    } 
 +}
 </code> </code>
  
-=== Attributes ===+=== Dynamic resolution ===
  
-Attributes can be used with short classes:+Just as with ''%%::%%'', developers may use variables to resolve inner classes, or refer to them by name directly via a string:
  
 <code php> <code php>
-#[MyAttribute] +// Using variables to dynamically instantiate inner classes: 
-class Password(#[SensitiveParameter] string $password);+$outer = "Outer"; 
 +$inner = "Inner"; 
 +$instance = new $outer:>$inner(); 
 + 
 +// Instantiating inner class dynamically via a fully qualified class string
 +$dynamicClassName = "Outer:>Inner"; 
 +$instance = new $dynamicClassName();
 </code> </code>
  
-=== Modifiers ===+This provides flexibility and backwards compatibility for dynamic code that may not expect an inner class.
  
-Short classes support readonly, final, and abstract:+==== Visibility from inner classes ====
  
-<code php> +Inner classes have access to their outer class’s private and protected methodsproperties, and inner classes. However, they do not have access to their siblings’ private and protected methods, properties, and inner classes.
-readonly class User(int $idstring $name);+
  
-final class Config(string $keymixed $value);+<code php> 
 +class User { 
 +    public private(set) string $name; 
 +    public private(set) string $email; 
 +     
 +    private function __construct(self:>Builder $builder) { 
 +        $this->name = $builder->name; 
 +        $this->email = $builder->email; 
 +    } 
 +     
 +    public readonly final class Builder { 
 +        public function __construct(public private(set) string|null $name = nullpublic private(set) string|null $email = null) {} 
 +         
 +        public function withEmail(string $email): self { 
 +            return new self($this->name, $email); 
 +        } 
 +         
 +        public function withName(string $name): self { 
 +            return new self($name, $this->email); 
 +        } 
 +         
 +        public function build(): User { 
 +            return new User($this); 
 +        } 
 +    } 
 +}
  
-abstract class Shape(float $area);+$user = new User:>Builder()->withName('Rob')->withEmail('rob@bottled.codes')->build();
 </code> </code>
  
-=== How it works ===+This enables usages such as builder patterns and other helper classes to succinctly encapsulate behavior.
  
-Short classes are purely syntactic sugar and compiled into standard class definitions during compile time.+==== Visibility from outside the outer class ====
  
-==== Inner Classes ==== +Inner classes are not visible outside their outer class unless they are publicProtected classes may be used and accessed from within their child classes.
- +
-Inner classes allow defining classes within other classes, following standard visibility rules. This allows developers to declare a class as ''%%private%%'' or ''%%protected%%'' and restrict its usage to the outer class. Inner classes may only be nested one level deep, may not be a parent class, and may not be declared ''%%abstract%%'':+
  
 <code php> <code php>
 class Outer { class Outer {
-    class Inner(public string $message); // using short syntax +    private class Other {} 
-     +    protected class Inner 
-    // using traditional syntax +        public function Foo() { 
-    private class PrivateInner { +            $bar = new Outer:>Inner(); // allowed 
-        public function __construct(public string $message) {}+            $bar = new Outer:>Other(); // allowed 
 +        }
     }     }
 } }
  
-$foo = new Outer::Inner('Hello, world!'); +class SubOuter extends Outer { 
-echo $foo->message; +    public function Foo() { 
-// outputs: Hello, world! +        $bar = new parent:>Inner(); // allowed to access protected inner class 
-$baz = new Outer::PrivateInner('Hello, world!'); +        $bar = new parent:>Other(); // Cannot access private inner class 'Outer:>Other' 
-// Fatal error: Uncaught Error: Cannot access private inner class Outer::PrivateInner +    } 
 +}
 </code> </code>
  
-=== Modifiers ===+Attempting to instantiate a private or protected inner class outside its outer class will result in a fatal error:
  
-Inner classes support modifiers such as ''%%public%%'', ''%%protected%%'', ''%%private%%'', ''%%final%%'' and ''%%readonly%%''. When using these as modifiers on an inner class, there are some intuitive rules:+<code php> 
 +new Outer:>Inner(); // Cannot access protected inner class 'Outer:>Inner' 
 +</code>
  
-  * ''%%public%%'', ''%%private%%'', and ''%%protected%%'' apply to the **visibility** of the inner class. +=== Method return type and argument declarations ===
-  * ''%%final%%'', and ''%%readonly%%'' apply **to the class itself**. +
-  * ''%%static%%'' is **not allowed** as a modifier since PHP does not support static classes and isn’t a property. +
-  * ''%%abstract%%'' is not allowed as an inner class **cannot** be parent classes.+
  
-=== Visibility Rules ===+Inner classes may only be used as a return type or argument declarations for methods and functions that have the same visibility or lesser. Thus returning a ''%%protected%%'' class type from a ''%%public%%'' method is not allowed, but is allowed from a ''%%protected%%'' or ''%%private%%'' method.
  
-Private and protected inner classes are only instantiatable within their outer class (or subclasses for protected) and may not be used as //type hints// outside their outer class.+^Inner Class Visibility^Method Visibility^Allowed^ 
 +|''%%public%%''        |''%%public%%''   |Yes    | 
 +|''%%public%%''        |''%%protected%%''|Yes    | 
 +|''%%public%%''        |''%%private%%''  |Yes    | 
 +|''%%protected%%''     |''%%public%%''   |No     | 
 +|''%%protected%%''     |''%%protected%%''|Yes    | 
 +|''%%protected%%''     |''%%private%%''  |Yes    | 
 +|''%%private%%''       |''%%public%%''   |No     | 
 +|''%%private%%''       |''%%protected%%''|No     | 
 +|''%%private%%''       |''%%private%%''  |Yes    |
  
-For example, you may return a private inner class from any method inside that same inner class or the outer class, but you may not use it as a type hint in a function outside the outer class:+Methods and functions outside the outer class are considered public from the perspective of an inner class. Attempting to declare return of a non-visible type will result in a ''%%TypeError%%'':
  
 <code php> <code php>
-class Box +class Outer 
-  private class Point(int $x, int $y); +    private class Inner {} 
-   +     
-  private self::Point $center; +    public function getInner(): self:>Inner 
-   +        return new self:>Inner(); 
-  public function __construct() +    }
-    $this->center = new self::Point(0, 0); +
-  } +
-   +
-  public function getCenter(): self::Point +
-    return $this->center; +
-  } +
-   +
-  public function setCenter(self::Point $center{ +
-    $this->center = $center; +
-  }+
 } }
  
-$box = new Box()+// Fatal error: Uncaught TypeError: Public method getInner cannot return private class Outer:>Inner 
-$center = $box->getCenter(); +new Outer()->getInner();
-$center->x = 10; +
-$box->setCenter($center); +
-var_dump($box);+
 </code> </code>
  
-Outputs:+=== Properties ===
  
-<code> +The visibility of a type declaration on a property must also not increase the visibility of an inner class. Thus, a public property cannot declare a private type. 
-object(Box)#1 (1) + 
-  ["center":"Box":private]=> +This gives a great deal of control to developers, preventing accidental misuse of inner classes. However, this **does not** preclude developers from returning a private/protected inner class, only from using them as a type declaration. The developer can use an interface or abstract class type declaration, or use a broader type such as ''%%object%%'', ''%%mixed%%'', or nothing at all: 
-  object(Box::Point)#2 (2) + 
-    ["x"]=> +<code php
-    int(10+class Outer 
-    ["y"]=> +    private class Inner implements FooBar {} 
-    int(0+     
-  }+    public function getInner(): FooBar { 
 +        return new self:>Inner(); // not an error 
 +    }
 } }
 </code> </code>
  
-However, if we try to use it outside the outer class as a type hint:+==== Accessing outer classes ==== 
 + 
 +Inner classes do not implicitly have access to an outer class instance. This design choice avoids implicit coupling between classes and keeps inner classes simpler, facilitating potential future extensions (such as adding an explicit outer keyword) without backward compatibility issues. 
 + 
 +Passing an outer instance explicitly remains an available option for accessing protected/private methods or properties. Thus inner classes may access outer class private/protected methods and properties if given an instance.
  
 <code php> <code php>
-function mutateBox(Box::Point $point): Box::Point +class Message { 
-    $point->10;+    public function __construct(private string $message, private string $from, private string $to) {} 
 +     
 +    public function Serialize(): string { 
 +        return new Message:>SerializedMessage($this)->message; 
 +    
 +     
 +    private class SerializedMessage { 
 +        public string $message; 
 +         
 +        public function __construct(Message $message) { 
 +            $this->message strlen($message->from) . $message->from . strlen($message->to) . $message->to . strlen($message->message) . $message->message; 
 +        } 
 +    }
 } }
- 
-$center = mutateBox($center); 
 </code> </code>
  
-We receive the following error:+==== Reflection ==== 
 + 
 +Several new methods are added to ''%%ReflectionClass%%'' to help support inspection of inner classes: 
 + 
 +<code php> 
 +$reflection = new ReflectionClass('\a\namespace\Outer:>Inner');
  
-<code+$reflection->isInnerClass(); // true 
-PHP Fatal error Private inner class Box::Point cannot be used in the global scope+$reflection->isPublic() || $reflection->isProtected() || $reflection->isPrivate(); // true 
 +$reflection->getName(); // \a\namespace\Outer:>Inner 
 +$reflection->getShortName(); // Outer:>Inner
 </code> </code>
  
-This gives a great deal of control to developers, preventing accidental misuse of inner classes. Developers may have the inner class implement an interface so that the programmer must code to the interfaceallowing large projects to enforce a consistent API.+For non-inner classes, ''%%ReflectionClass::isInnerClass()%%'' returns false.
  
-=== Inheritance ===+==== Autoloading ====
  
-Inner classes have inheritance similar to static properties; this allows you to redefine an inner class in a subclass, allowing rich hierarchies.+Inner classes are never autoloaded, only their outermost class is autoloaded. If the outermost class does not exist, then their inner classes do not exist. 
 + 
 +==== Usage ==== 
 + 
 +Inner classes may be defined in the body of any class-like structure, including but not limited to
 + 
 +  * in a class body 
 +  * in an anonymous class body 
 +  * in an enum body 
 +  * in a trait body 
 +  * in an interface body 
 + 
 +Note: While traits and interfaces may define inner classes, classes using these traits or implementing these interfaces do not inherit their inner classes. Inner classes remain strictly scoped and bound to their defining context only. 
 + 
 +==== Outer class effects ==== 
 + 
 +Inner classes are fully independent of their outer class’s declaration modifiers. Outer class modifiers such as abstract, final, or readonly do not implicitly cascade down or affect the inner classes defined within them. 
 + 
 +Specifically: 
 + 
 +  * An abstract outer class can define concrete (non-abstract) inner classes. Inner classes remain instantiable, independent of the outer class’s abstractness. 
 +  * A final outer class does not force its inner classes to be final. Inner classes within a final class can be extended internally, providing flexibility within encapsulation boundaries. 
 +  * A readonly outer class can define mutable inner classes. This supports internal flexibility, allowing the outer class to maintain immutability in its external API while managing state changes internally via inner classes. 
 + 
 +Examples: 
 + 
 +<code php> 
 +abstract class Service { 
 +    // Valid: Inner class is not abstract, despite the outer class being abstract. 
 +    public class Implementation { 
 +        public function run(): void {} 
 +    } 
 +
 + 
 +// Allowed; abstract outer class does not force inner classes to be abstract. 
 +new Service:>Implementation(); 
 +</code>
  
 <code php> <code php>
-readonly class Point(int $x, int $y);+readonly class ImmutableCollection { 
 +    private array $items;
  
-class Geometry { +    public function __construct(array $items) { 
-    public array $points; +        $this->items = $items;
-    protected function __construct(Point ...$points) { +
-        $this->points = $points;+
     }     }
-     + 
-    public class FromPoints extends Geometry { +    public function getMutableBuilder(): self:>Builder 
-        public function __construct(Point ...$points) { +        return new self:>Builder($this->items);
-            parent::__construct(...$points); +
-        }+
     }     }
-     + 
-    public class FromCoordinates extends Geometry +    public class Builder { 
-        public function __construct(int ...$coordinates) { +        private array $items; 
-            $points []; + 
-            for ($i = 0; $i < count($coordinates); $i += 2) { +        public function __construct(array $items) { 
-                $points[] = new Point($coordinates[$i], $coordinates[$i + 1]); +            $this->items = $items;
-            } +
-            parent::__construct(...$points);+
         }         }
-    } 
-} 
  
-class Triangle extends Geometry { +        public function add(mixed $item): self 
-    protected function __construct(public Point $p1, public Point $p2, public Point $p3) { +            $this->items[] = $item
-        parent::__construct($p1, $p2, $p3); +            return $this;
-    } +
-     +
-    public class FromPoints extends Triangle { +
-        public function __construct(Point $p1, Point $p2, Point $p3) { +
-            parent::__construct($p1, $p2, $p3);+
         }         }
-    } + 
-     +        public function build(): ImmutableCollection 
-    public class FromCoordinates extends Triangle { +            return new ImmutableCollection($this->items);
-        public function __construct(int $x1, int $y1, int $x2, int $y2, int $x3, int $y3) { +
-            parent::__construct(new Point($x1, $y1), new Point($x2, $y2), new Point($x3, $y3));+
         }         }
     }     }
 } }
- 
-$t = new Triangle::FromCoordinates(0, 0, 1, 1, 2, 2); 
- 
-var_dump($t instanceof Triangle); // true 
-var_dump($t instanceof Geometry); // true 
-var_dump($t instanceof Triangle::FromCoordinates); // true 
 </code> </code>
  
-Howeverno classes may not inherit from inner classesbut inner classes may inherit from other classes, including the outer class.+In this exampleeven though ImmutableBuilder is a mutable inner class within a readonly outer class, the outer class maintains its immutability externally, while inner classes help internally with state management or transitional operations.
  
-=== Names ===+==== Abstract inner classes ====
  
-Inner classes may not have any name that conflicts with constant or static property of the same name.+It is worth exploring what an ''%%abstract%%'' inner class means and how it works. Abstract inner classes are allowed to be the parent of any class that can see them. For example, private abstract class may only be inherited by subclasses in the same outer class. A protected abstract class may be inherited by an inner class in a subclass of the outer class or an inner class in the same outer class. However, this is not required by subclasses of the outer class. 
 + 
 +Abstract inner classes may not be instantiated, just as abstract outer classes may not be instantiated.
  
 <code php> <code php>
-class Foo +class OuterParent 
-    const Bar = 'bar'; +    protected abstract class InnerBase {}
-    class Bar(public string $message); +
-     +
-    // Fatal error: Uncaught Error: Cannot redeclare Foo::Bar+
 } }
  
-class Foo +// Middle is allowed, does not have to implement InnerBase 
-    static $Bar = 'bar'; +class Middle extends OuterParent {} 
-    class Bar(public string $message); + 
-     +// Last demonstrates extending the abstract inner class explicitly. 
-    // Fatal error: Uncaught ErrorCannot redeclare Foo::$Bar+class Last extends OuterParent { 
 +    private abstract class InnerExtended extends OuterParent:>InnerBase {}
 } }
 </code> </code>
Line 286: Line 463:
 ==== To Existing Extensions ==== ==== To Existing Extensions ====
  
-Extensions accepting class names may need to be updated to support ''%%::%%'' in class names. None were discovered during testing, but it is possible there are extensions that may be affected.+Extensions accepting class names may need to be updated to support ''%%:>%%'' in class names. None were discovered during testing, but it is possible there are unbundled extensions that may be affected.
  
 ==== To Opcache ==== ==== To Opcache ====
  
 This change introduces a new opcode, AST, and other changes that affect opcache. These changes are included as part of the PR that implements this feature. This change introduces a new opcode, AST, and other changes that affect opcache. These changes are included as part of the PR that implements this feature.
 +
 +==== To Tooling ====
 +
 +Tooling that uses AST or tokenization may need to be updated to support the new syntax, such as syntax highlighting, static analysis, and code generation tools.
  
 ===== Open Issues ===== ===== Open Issues =====
Line 302: Line 483:
 ===== Future Scope ===== ===== Future Scope =====
  
-  * inner enums+  * Inner enums 
 +  * Inner interfaces 
 +  * Inner traits 
 +  * ''%%Outer%%'' keyword for easily accessing outer classes
  
 ===== Proposed Voting Choices ===== ===== Proposed Voting Choices =====
Line 311: Line 495:
 ===== Patches and Tests ===== ===== Patches and Tests =====
  
-A complete implementation is available [[https://github.com/php/php-src/compare/master...bottledcode:php-src:rfc/short-class2?expand=1|on GitHub]].+To be completed.
  
 ===== Implementation ===== ===== Implementation =====
Line 324: Line 508:
 ===== Rejected Features ===== ===== Rejected Features =====
  
-  * "evolvable" syntax: A ->with() function built into short classes.+TBD
  
rfc/short-and-inner-classes.1741212772.txt.gz · Last modified: 2025/03/05 22:12 by withinboredom