Description
I researched the existing PHP proposals around object initialization before writing this, and found the previous Object Initializer RFC from 2019.
That RFC proposed syntax like:
$customer = new Customer {
id = 123,
name = "John Doe",
};
It was declined, and its scope was limited to property initialization.
This proposal builds on that idea and extends it into something more general: an Object Initialization Block.
The problem
When an object needs initialization beyond constructor arguments, PHP currently requires either a temporary variable:
$object = new Foo();
$object->foo = 1;
$object->bar = 'text';
$object->more();
or a fluent/method-chaining API:
$object = (new Foo())
->setFoo(1)
->setBar('text')
->more();
The first approach requires a separate variable and multiple statements. The second requires a fluent API and makes properties less useful as part of the object's interface.
Several existing language features can be used to work around parts of this problem, but they each address only one aspect:
- Variadic parameters can be used to pass arbitrary initialization data, but become particularly difficult to reason about with inheritance and long constructor call chains. Mixing variadics with named arguments also introduces awkward edge cases around named parameters and overriding values.
- Named arguments make passing values clearer, but they cannot express method calls or arbitrary initialization logic.
- Constructor property promotion reduces boilerplate for simple property assignment, but it cannot express method calls either. It also becomes increasingly awkward when property hooks are involved: putting everything into the constructor parameter list is not a particularly readable way to define an object's initialization interface. Alternatively, the hooks have to live separately on the class while the constructor merely transfers its parameters to the properties.
These approaches therefore feel like isolated solutions to different symptoms of the same problem, rather than a general solution to object initialization.
They each work well within their intended scope, but none provides a natural way to say: create this object, then perform these initialization operations on that object.
It seems that we have explored several ways around the problem while perhaps overlooking the most direct model: an initialization block attached to the object creation itself.
The proposal
Allow a newly created object to be followed by an initialization block:
$object = new Foo {
$this->foo = 1;
$this->bar = 'text';
$this->more();
};
The block would execute in the context of the newly created object, with $this referring to that object.
Conceptually, this would be equivalent to:
$object = new Foo();
$object->foo = 1;
$object->bar = 'text';
$object->more();
but keeps the initialization as a single expression.
Unlike the previous Object Initializer RFC, the block would not be restricted to property assignments. It could contain arbitrary initialization logic:
$object = new Foo {
$this->foo = calculateFoo();
$this->bar = 'text';
if ($this->foo > 10) {
$this->more();
}
};
This also makes normal properties and property hooks usable without requiring a fluent API.
Why revisit this?
The original Object Initializer RFC was a useful starting point, but PHP has evolved since then, particularly with property hooks.
The broader idea is to provide one general mechanism instead of requiring different workarounds depending on what needs to happen during initialization.
Constructors remain useful for invariants and required dependencies. Named arguments remain useful for method arguments. Property promotion remains useful for simple constructor-to-property mapping. Fluent APIs remain useful where chaining is actually part of an API.
But none of these needs to be stretched into something it was not designed to solve.
An Object Initialization Block would provide the missing general-purpose mechanism for initializing an already-created object.
This is intentionally presented first as a discussion/proposal to find out whether the idea has enough interest to be worth pursuing further.
Description
I researched the existing PHP proposals around object initialization before writing this, and found the previous Object Initializer RFC from 2019.
That RFC proposed syntax like:
It was declined, and its scope was limited to property initialization.
This proposal builds on that idea and extends it into something more general: an Object Initialization Block.
The problem
When an object needs initialization beyond constructor arguments, PHP currently requires either a temporary variable:
or a fluent/method-chaining API:
The first approach requires a separate variable and multiple statements. The second requires a fluent API and makes properties less useful as part of the object's interface.
Several existing language features can be used to work around parts of this problem, but they each address only one aspect:
These approaches therefore feel like isolated solutions to different symptoms of the same problem, rather than a general solution to object initialization.
They each work well within their intended scope, but none provides a natural way to say: create this object, then perform these initialization operations on that object.
It seems that we have explored several ways around the problem while perhaps overlooking the most direct model: an initialization block attached to the object creation itself.
The proposal
Allow a newly created object to be followed by an initialization block:
The block would execute in the context of the newly created object, with
$thisreferring to that object.Conceptually, this would be equivalent to:
but keeps the initialization as a single expression.
Unlike the previous Object Initializer RFC, the block would not be restricted to property assignments. It could contain arbitrary initialization logic:
This also makes normal properties and property hooks usable without requiring a fluent API.
Why revisit this?
The original Object Initializer RFC was a useful starting point, but PHP has evolved since then, particularly with property hooks.
The broader idea is to provide one general mechanism instead of requiring different workarounds depending on what needs to happen during initialization.
Constructors remain useful for invariants and required dependencies. Named arguments remain useful for method arguments. Property promotion remains useful for simple constructor-to-property mapping. Fluent APIs remain useful where chaining is actually part of an API.
But none of these needs to be stretched into something it was not designed to solve.
An Object Initialization Block would provide the missing general-purpose mechanism for initializing an already-created object.
This is intentionally presented first as a discussion/proposal to find out whether the idea has enough interest to be worth pursuing further.