Hello internals,
I'd like to explore the possibility of adding a first-class callable syntax
for object constructors:
$factory = new Foo(...);
The idea is that this expression would produce a Closure which, when
invoked, calls the constructor with the provided arguments:
$factory = new Foo(...);
$object = $factory($arg1, $arg2);
This would conceptually mirror the existing first-class callable notation
for functions and methods: trim(...), $object->method(...),
Foo::method(...).
Today, the equivalent form requires boilerplate such as:
$factory = static fn($arg): Foo => new Foo($arg);
or defining a static factory:
class Foo
{
public static function new($arg): self
{
return new self($arg);
}
}
$factory = Foo::new(...);
However, the latter is not possible for 3rd-party classes.
Question for Larry and Arnaud:
In PFA v2
https://wiki.php.net/rfc/partial_function_application_v2#constructors,
you note that constructor references pose significant technical challenges.
Could you elaborate on what those challenges are and whether they are
fundamental, or potentially addressable with a more limited or explicit
syntax such as new Foo(...)?
You also mention that "the use cases for partially applying a constructor
are few, especially now that we have lazy objects (as of PHP 8.4)." I tend
to disagree. For cases like:
$numbers = array_map(new BcMath\Number(...), $numericStrings);
lazy objects do not help, and a constructor-as-callable form remains
valuable.
Best regards,
Valentin
Hi Valentin,
On Thu, Nov 20, 2025 at 2:20 PM Valentin Udaltsov
udaltsov.valentin@gmail.com wrote:
Question for Larry and Arnaud:
In PFA v2, you note that constructor references pose significant technical challenges.
Could you elaborate on what those challenges are and whether they are fundamental, or potentially addressable with a more limited or explicit syntax such asnew Foo(...)?
One issue is that partial application needs to resolve the function
being applied, but constructors can not be resolved without
instantiating the class first (at least, not on all classes). So new Foo(...) would need to instantiate Foo, resolve the constructor, and
discard the instance, before creating the PFA.
This is something that could be addressed as a follow up to PFA v2.
Best Regards,
Arnaud
Hi Valentin,
On Thu, Nov 20, 2025 at 2:20 PM Valentin Udaltsov
udaltsov.valentin@gmail.com wrote:Question for Larry and Arnaud:
In PFA v2, you note that constructor references pose significant technical challenges.
Could you elaborate on what those challenges are and whether they are fundamental, or potentially addressable with a more limited or explicit syntax such asnew Foo(...)?One issue is that partial application needs to resolve the function
being applied, but constructors can not be resolved without
instantiating the class first (at least, not on all classes). Sonew Foo(...)would need to instantiate Foo, resolve the constructor, and
discard the instance, before creating the PFA.This is something that could be addressed as a follow up to PFA v2.
Best Regards,
Arnaud
I will defer to Arnaud on the details. For my part, I have no conceptual objection to partialing constructors. The reason it was omitted from PFAv2 was basically "it's hard and complicated and there's enough going on here as is."
If someone else wants to do a follow up RFC for FCC/PFA on constructors, I would not be opposed.
--Larry Garfield
Hi Valentin,
On Thu, Nov 20, 2025 at 2:20 PM Valentin Udaltsov
udaltsov.valentin@gmail.com wrote:Question for Larry and Arnaud:
In PFA v2, you note that constructor references pose significant technical challenges.
Could you elaborate on what those challenges are and whether they are fundamental, or potentially addressable with a more limited or explicit syntax such asnew Foo(...)?One issue is that partial application needs to resolve the function
being applied, but constructors can not be resolved without
instantiating the class first (at least, not on all classes).
To clarify, constructors are normally resolved after creating an
object, by calling the get_constructor() handler on the object. The
handler isn't known before creating the object, at least for internal
classes, so we can't resolve a constructor without creating an object
first. This would have to be addressed in order to support partial
application of classes.
Hi Valentin,
On Thu, Nov 20, 2025 at 2:20 PM Valentin Udaltsov
udaltsov.valentin@gmail.com wrote:Question for Larry and Arnaud:
In PFA v2, you note that constructor references pose significant technical challenges.
Could you elaborate on what those challenges are and whether they are fundamental, or potentially addressable with a more limited or explicit syntax such asnew Foo(...)?One issue is that partial application needs to resolve the function
being applied, but constructors can not be resolved without
instantiating the class first (at least, not on all classes).To clarify, constructors are normally resolved after creating an
object, by calling the get_constructor() handler on the object. The
handler isn't known before creating the object, at least for internal
classes, so we can't resolve a constructor without creating an object
first. This would have to be addressed in order to support partial
application of classes.
Oh so one more reason to get rid of the get_constructor() handler then.
Would the approach that I started prototyping in
https://github.com/php/php-src/pull/19797 help as we would know the
zend_function the moment we have the CE?
Best regards,
Gina P. Banyard
Hi Gina,
Oh so one more reason to get rid of the get_constructor() handler then.
Would the approach that I started prototyping in
https://github.com/php/php-src/pull/19797 help as we would know the
zend_function the moment we have the CE?
This would help as long as the get_constructor() handler is also
removed (so that zend_class_entry.constructor is always the truth), or
moved to zend_class_entry.
Best Regards,
Arnaud
I'd like to explore the possibility of adding a first-class callable syntax
for object constructors:$factory = new Foo(...);The idea is that this expression would produce a Closure which, when
invoked, calls the constructor with the provided arguments:$factory = new Foo(...); $object = $factory($arg1, $arg2);
Something worth clarifying here is that what you want is not just to call the constructor, but to create the object. In some languages, that's the same thing - there's a base object constructor which has to be called - but in PHP, the constructor itself is just a callback hook, called after the object exists.
And that's where the complexity comes in: "new Foo" isn't a function call, it's an interpreter operation.
Here is Nikita's explanation of the issue in the First Class Callable RFC https://wiki.php.net/rfc/first_class_callable_syntax
[Begin Quote]
The new Foo() syntax is not considered a call, and as such also not supported by the new Foo(...) syntax. It should be noted that there is also no way to express object creation with traditional callable syntax, and it is thus also not supported by Closure::fromCallable().
The general expectation is that new Foo(...) would be creating a new instance of Foo on each call, rather than creating a single instance of Foo and then repeatedly calling the constructor. To support this, it would effectively be necessary to generate a trampoline function of the form
fn(...$args) => new Foo(...$args)
and acquire a callable to that trampoline instead. While certainly possible, this takes a step backwards from the straightforward semantics of the foo(...) syntax for ordinary calls.
[End Quote]
Rowan Tommins
[IMSoP]