Skip to content
Draft
302 changes: 302 additions & 0 deletions drafts/short-class.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,302 @@
# PHP RFC: Inner Classes with Short Syntax

* Version: 0.1
* Date: 2025-02-08
* Author: Rob Landers, rob@bottled.codes
* Status: Draft (or Under Discussion or Accepted or Declined)
* First Published at: <http://wiki.php.net/rfc/short-class>

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick (assertive)

RFC Metadata Header:
The header clearly presents the RFC title, version, date, author, status, and publication link. As noted in the static analysis hints, you might consider shortening “Under Discussion” to a briefer alternative for clarity.

🧰 Tools
🪛 LanguageTool

[style] ~6-~6: ‘Under Discussion’ might be wordy. Consider a shorter alternative.
Context: ..., rob@bottled.codes * Status: Draft (or Under Discussion or Accepted or Declined) * First Publis...

(EN_WORDINESS_PREMIUM_UNDER_DISCUSSION)

## Introduction

This RFC proposes a new short syntax for class/enum definitions in PHP and the ability to embed these classes within other
classes.

## Proposal

Data transfer objects (DTOs) are a common pattern in PHP applications and are usually simple data structures that hold
data and have no behavior.
With this RFC,
we propose a simple and concise syntax for defining these classes, looking almost like named anonymous classes, as well as
the ability to embed them within other classes.

### Short Class Syntax

The proposed syntax for a short class definition is as follows: a keyword `class`,
followed by the class name, then a list of public properties enclosed in parentheses.
Optionally, a list of traits, interfaces, and a parent class may be defined.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick (assertive)

Short Class Syntax Explanation:
The description clearly explains that a short class definition uses a single-line syntax with public properties in parentheses. For further clarity, consider mentioning the required order when mixing traits, interfaces, and parent classes.

```php
class Point(int $x, int $y);
```

This is equivalent to the following full class definition:

```php
class Point {
public function __construct(public int $x, public int $y) {}
}
```

Any properties defined within the parenthesis are defined as a public property of the class.

#### Default Values

Default values may be provided for properties:

```php
class Point(int $x = 0, int $y = 0);
```

#### Inheritance and Behavior

With class short syntax, no behavior may be defined, yet it can still utilize traits, interfaces, and other classes.

```php
class Point(int $x, int $y) extends BasePoint implements JsonSerializable use PointTrait, Evolvable;
```

Note that the original constructor from any parent class is overridden and not called by the short syntax.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick (assertive)

Inheritance and Behavior Section:
This section explains that while behavior isn’t defined within the short syntax, inheritance, interfaces, and trait usage are supported. The combined example using extends, implements, and use is innovative; however, clarifying the ordering or any special syntax rules (especially for trait usage) would help prevent ambiguity.

#### Empty Classes

Short classes may also be empty:

```php
class Point() extends BasePoint use PointTrait;
```

#### Attributes

Attributes may also be used with short classes:

```php
class Password(#[SensitiveParameter] string $password);
```

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick (assertive)

Attributes in Short Classes:
Including attributes directly within the short class declaration is a forward-thinking addition. It would be beneficial to note any PHP version requirements for attribute support to set proper expectations for adopters.

### Short enums

Enums are a common pattern in PHP applications and are usually simple data structures that hold a set of constants.
This RFC includes a proposal for short enums:

```php
enum Color(Red, Green, Blue);
```

This is equivalent to the following full enum definition:

```php
enum Color {
case Red;
case Green;
case Blue;
}
```

### Inner Classes

Inner classes are classes that are defined within another class.

```php
class Foo {
class Bar(public string $message);
enum Baz(One, Two, Three);

private class Baz {
public function __construct(public string $message) {}
}
}

$foo = new Foo::Bar('Hello, world!');
echo $foo->message;
// outputs: Hello, world!
$baz = new Foo::Baz('Hello, world!');
// Fatal error: Uncaught Error: Cannot access private class Foo::Baz
```
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick (assertive)

⚠️ Potential issue

Inner Classes Demonstration:
The inner classes feature is illustrated with practical examples. However, there appears to be a naming conflict: two entities named Baz are defined—one as an enum and one as a private class. Please clarify if this is an intentional demonstration of conflict handling or if distinct names should be used to avoid ambiguity.


Inner classes have scope similar to properties, which applies to parameters and returns types as well.

#### Modifiers

Properties support modifiers such as `public`, `protected`, and `private` as well as `static`, `final` and `readonly`.
When using these as modifiers on an inner class, there are some intuitive rules:

- `public`, `private`, and `protected` apply to the visibility of the class.
- `static`, `final`, and `readonly` apply to the class itself.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick (assertive)

Modifiers for Inner Classes:
The modifiers section clearly distinguishes between visibility modifiers and those affecting the class behavior (static, final, readonly). A slight improvement in punctuation in the bullet list may aid readability.

🧰 Tools
🪛 LanguageTool

[uncategorized] ~123-~123: Loose punctuation mark.
Context: ...re are some intuitive rules: - public, private, and protected apply to the...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~124-~124: Loose punctuation mark.
Context: ... the visibility of the class. - static, final, and readonly apply to the cl...

(UNLIKELY_OPENING_PUNCTUATION)

Thus, an inner class with the modifier `private readonly` is only accessible within the class
and any instances are readonly.

#### Visibility

A `private` or `protected` inner class is only accessible within the class it is defined in
(or its subclasses in the case of protected classes).
This also applies to methods and return types.

```php
class Foo {
private class Bar(public string $message);

// Fatal error: Uncaught Error: Cannot return private class Foo::Bar
public function getMessage(): Bar {
return new Bar('Hello, world!');
}
}
```

#### Accessing Inner Classes

From outside the class, public inner classes may be accessed using the `::` operator:

```php
new Foo::Bar('Hello, world!');
```

This may also be used from inside the class or in subclasses at the developer’s discretion. Alternatively, inner classes
may be accessed using `self::` or `static::` from inside the class, or just using the name itself:

```php

private function getBar(): Foo::Bar {
$a = new Bar('Hello, world!');
$b = new self::Bar('Hello, world!');
$c = new static::Bar('Hello, world!');
$d = new Foo::Bar('Hello, world!');
}

```

Note that inner classes effectively "shadow" outer classes of the same name:

```php
readonly class Vect(int $x, int $y);

class Foo {
class Vect(int $x, int $y, int $z);

// Vect is Foo::Vect not \Vect
public function __construct(public Vect $vect) {}
}
```

#### Names

Inner classes may not have any name that conflicts with a constant or static property of the same name.

```php
class Foo {
const Bar = 'bar';
class Bar(public string $message);

// Fatal error: Uncaught Error: Cannot redeclare Foo::Bar
}

class Foo {
static $Bar = 'bar';
class Bar(public string $message);

// Fatal error: Uncaught Error: Cannot redeclare Foo::Bar
}
```
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick (assertive)

Naming Conventions and Conflicts:
The examples illustrate how inner classes can shadow outer classes and demonstrate conflicts with constants or static properties. Including some best-practice guidelines or naming recommendations could help developers avoid inadvertent ambiguities in their implementations.


These rules are to prevent developer confusion because these instantiations all look similar,
however, the following all result in the same inner class being instantiated:

```php
new (Foo::Bar);
new (Foo::$Bar);
new Foo::Bar();
```
Comment on lines +418 to +448
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick (assertive)

Instantiating Inner Classes – Potential Ambiguity:
The demonstration that different instantiation styles (e.g., new (Foo::Bar), new (Foo::$Bar), new Foo::Bar()) yield the same result is informative. Consider adding a brief note on best practices to ensure code clarity when utilizing these various styles.


## Backward Incompatible Changes

Creating a new instance from an existing static member is now allowed:

```php
class Foo {
public const Bar = 'bar';
}

new Foo::Bar(); // previously this is a syntax error, but now results in creating a new "bar" object.
```
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick (assertive)

Backward Incompatible Change Clarification:
Allowing instantiation from an existing static member is a significant change. While the provided example is clear, a short explanation of the rationale behind this decision could help developers understand its broader implications on legacy code.


## Proposed PHP Version(s)

List the proposed PHP versions that the feature will be included in. Use
relative versions such as "next PHP 8.x" or "next PHP 8.x.y".

## RFC Impact

### To SAPIs

Describe the impact to CLI, Development web server, embedded PHP etc.

### To Existing Extensions

Will existing extensions be affected?

### To Opcache

It is necessary to develop RFC's with opcache in mind, since opcache is
a core extension distributed with PHP.

Please explain how you have verified your RFC's compatibility with
opcache.

### New Constants

Describe any new constants so they can be accurately and comprehensively
explained in the PHP documentation.

### php.ini Defaults

If there are any php.ini settings then list: \* hardcoded default values
\* php.ini-development values \* php.ini-production values

## Open Issues

Make sure there are no open issues when the vote starts!

## Unaffected PHP Functionality

List existing areas/features of PHP that will not be changed by the RFC.

This helps avoid any ambiguity, shows that you have thought deeply about
the RFC's impact, and helps reduces mail list noise.

## Future Scope

This section details areas where the feature might be improved in
future, but that are not currently proposed in this RFC.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick (assertive)

Future Scope Section – Minor Language Update:
For consistency with standard American English, consider changing “in future” on line 268 to “in the future.”

🧰 Tools
🪛 LanguageTool

[locale-violation] ~268-~268: The phrase ‘in future’ is British English. Did you mean: “in the future”?
Context: ...eas where the feature might be improved in future, but that are not currently proposed in...

(IN_FUTURE)

## Proposed Voting Choices

Include these so readers know where you are heading and can discuss the
proposed voting options.

## Patches and Tests

Links to any external patches and tests go here.

If there is no patch, make it clear who will create a patch, or whether
a volunteer to help with implementation is needed.

Make it clear if the patch is intended to be the final patch, or is just
a prototype.

For changes affecting the core language, you should also provide a patch
for the language specification.

## Implementation

After the project is implemented, this section should contain - the
version(s) it was merged into - a link to the git commit(s) - a link to
the PHP manual entry for the feature - a link to the language
specification section (if any)

## References

Links to external references, discussions or RFCs

## Rejected Features

Keep this updated with features that were discussed on the mail lists.
9 changes: 5 additions & 4 deletions drafts/template.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
# PHP RFC: Your Title Here

\* Version: 0.9 \* Date: 2013-02-24 (use today's date here) \* Author:
Your Name, your_email_address@example.com \* Status: Draft (or Under
Discussion or Accepted or Declined) \* First Published at:
<http://wiki.php.net/rfc/your_rfc_name>
* Version: 0.9
* Date: 2013-02-24 (use today's date here)
* Author: Your Name, your_email_address@example.com
* Status: Draft (or Under Discussion or Accepted or Declined)
* First Published at: <http://wiki.php.net/rfc/your_rfc_name>
Comment on lines +3 to +7
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick (assertive)

Metadata Formatting Consistency:
The metadata block is neatly restructured, improving overall readability. However, consider refining the status line by replacing “Under Discussion” with a shorter, more concise alternative (e.g. “Draft” or “Proposed”) to better align with clear, succinct language.

🧰 Tools
🪛 LanguageTool

[style] ~6-~6: ‘Under Discussion’ might be wordy. Consider a shorter alternative.
Context: ...ddress@example.com * Status: Draft (or Under Discussion or Accepted or Declined) * First Publis...

(EN_WORDINESS_PREMIUM_UNDER_DISCUSSION)


This is a suggested template for PHP Request for Comments (RFCs). Change
this template to suit your RFC. Not all RFCs need to be tightly
Expand Down
Loading