[RFC] Callable constructors

php.internals

Dan Ackroyd

10 years ago
Hello internals, I've written a small RFC to make it possible to call constructors of objects as a callable, rather than only being able to call them through the 'new' language construct. https://wiki.php.net/rfc/callableconstructors After gathering informal feedback for the RFC, one person said that they felt it needed more of an emphasis on why it should be implemented. I wanted to keep the actual RFC short, in the hope that more people would read it in it's entirety, and also wanted to leave library specific code out of the RFC. So, as an addendum to the RFC text: I use the Auryn* DIC library. What I've wanted to do, and should be able to do in my opinion, is this: $injector->delegate('FooInterface', 'FooImplementation::__construct'); Which tells the injector "Whenever something requests an object that implements FooInterface as a dependency, just execute the FooImplementation constructor to make that object". If constructors had always been callable in PHP, this would be a standard thing to do and not controversial imo. It's only due to reasons lost in the mists of time, that object instantiation can only be invoked via 'new' that it's not possible currently, and so needs an RFC to change. As for the 'BC break' - I would be interested in hearing if anyone actually (admits to) having any code that would be affected by it. I think possibly the best way to manage this BC break, would be to make call_user_function($fn) behave the same as $fn(), when $fn = 'Foo::__construct' in a 7.0.x release, before adding the new functionality in 7.1.0. That would allow people to upgrade to a version where the changed behaviour breaks entirely, and so they can fix their code to use the correct calling semantics, before adding the new functionality in a later version. That give a clear way for people to detect problems, rather than it being a subtle change which is hard to detect. However I remain open to ideas on how to manage it better. cheers Dan * https://github.com/rdlowrey/auryn

Andrew Faulds

10 years ago
Hi Dan, Dan Ackroyd wrote:
> I've written a small RFC to make it possible to call constructors of > objects as a callable, rather than only being able to call them > through the 'new' language construct. > > https://wiki.php.net/rfc/callableconstructors
While I like the concept, I dislike the execution. My particular concern is that this makes __construct magic. It is a so-called "magic method" already, which is why it is prefixed with two underscores, but like all magic methods, it isn't the method itself that is "magic". __construct itself is just a method, you can call it directly (for example, parent::__construct()). Where the magic lies is in what calls it: when an object is created with `new`, __construct is automatically called. Similarly, __toString is just a normal method you can call like any other, and is only "magic" because when an object is converted to a string, __toString is called. Your proposal, however, would change this. Instead of __construct being a normal method which merely initialises the object it is called on, it would now become truly magical and actually implicitly create the object (without the author of the method having made it do so), but only in certain circumstances (not when called within a class, presumably). Furthermore, it becomes a strange beast PHP has not known until now: a method that is simultaneously static (Foo::__construct creates a new Foo) and an instance method (parent::__construct() operates on $this), with the two having different behaviour. Instead of changing __construct to implicitly create the object it acts on in certain contexts, I would suggest a simpler approach: add a magic ::new() static method that exists on all classes (think ::class, although that is a constant). Foo::new() would work identically to new Foo(), and would solve your use case. It would be more intuitive, I think, and it avoids the problems of changing __construct. Thanks.
-- Andrea Faulds https://ajf.me/

Adam Harvey

10 years ago
On 25 February 2016 at 09:40, Andrea Faulds <ajf@ajf.me> wrote:
> Instead of changing __construct to implicitly create the object it acts on > in certain contexts, I would suggest a simpler approach: add a magic ::new() > static method that exists on all classes (think ::class, although that is a > constant). Foo::new() would work identically to new Foo(), and would solve > your use case. It would be more intuitive, I think, and it avoids the > problems of changing __construct.
(Un?)fortunately, new() is a valid method name for userland classes in PHP 7.0. Adam

Andrew Faulds

10 years ago
Hi Adam, Adam Harvey wrote:
> On 25 February 2016 at 09:40, Andrea Faulds <ajf@ajf.me> wrote: >> Instead of changing __construct to implicitly create the object it acts on >> in certain contexts, I would suggest a simpler approach: add a magic ::new() >> static method that exists on all classes (think ::class, although that is a >> constant). Foo::new() would work identically to new Foo(), and would solve >> your use case. It would be more intuitive, I think, and it avoids the >> problems of changing __construct. > > (Un?)fortunately, new() is a valid method name for userland classes in PHP 7.0.
It is indeed, but that means the risk of backwards compatibility breakage is quite low. PHP 7 hasn't been out for long. Thanks!
-- Andrea Faulds https://ajf.me/

Rowan Collins

10 years ago
On 25/02/2016 17:40, Andrea Faulds wrote:
> Dan Ackroyd wrote: >> I've written a small RFC to make it possible to call constructors of >> objects as a callable, rather than only being able to call them >> through the 'new' language construct. >> >> https://wiki.php.net/rfc/callableconstructors > > While I like the concept, I dislike the execution.
Snipped for brevity, but I agree with your sentiment here. Making __construct more magic seems like an imperfect solution to this. I'm not sure making a new magic method (new, __new, etc) is much better though, since it would serve such a limited purpose. It has come up before in various contexts that PHP lacks a true callable type, in the sense that you never "construct" a callable, you just *use* something as a callable. I think callable constructors would fit better as part of an API that solved this. For instance, there could be a (magic) Callable class with various named constructors: - Callable::forFunction(string $function_name) - Callable::forMethod(object $instance, string $method_name) - Callable::forStaticMethod(string $class_name, string $method_name) - Callable::fromPaamayimNekudotayim(string $class_colon_colon_method) // OK, maybe not ;) This isn't perfect, because the parameters would still look like strings to static analysis, rather than being proper compiled-in references, but it's nicer than repeatedly analysing an array or string to evaluate is_callable() or type-checks. Then we could add to that a special case for constructors: - Callable::forConstructor(string $class_name) This would be roughly equivalent to (and polyfillable with): return function (...$args) use ( $class_name ) { return new $class_name(...$args); }; Regards,
-- Rowan Collins [IMSoP]

Andrew Faulds

10 years ago
Hi Rowan, Rowan Collins wrote:
> On 25/02/2016 17:40, Andrea Faulds wrote: > > Snipped for brevity, but I agree with your sentiment here. Making > __construct more magic seems like an imperfect solution to this. I'm not > sure making a new magic method (new, __new, etc) is much better though, > since it would serve such a limited purpose.
Yeah, I do wonder if ::new would really be worth it.
> > Then we could add to that a special case for constructors: > > - Callable::forConstructor(string $class_name) >
Oh, that's quite a clean solution, I like that. Heck, no need for Callable, we already have ->getClosure() in Reflection. A modified version of that for constructors could work (ReflectionClass::getConstructorClosure() ?). Thanks.
-- Andrea Faulds https://ajf.me/

Nikita

10 years ago
On Fri, 26 Feb 2016 14:28:19 +0300, Andrea Faulds <ajf@ajf.me> wrote:
> Hi Rowan, > > Rowan Collins wrote: >> On 25/02/2016 17:40, Andrea Faulds wrote: >> >> Snipped for brevity, but I agree with your sentiment here. Making >> __construct more magic seems like an imperfect solution to this. I'm not >> sure making a new magic method (new, __new, etc) is much better though, >> since it would serve such a limited purpose. > > Yeah, I do wonder if ::new would really be worth it. > >> >> Then we could add to that a special case for constructors: >> >> - Callable::forConstructor(string $class_name) >> > > Oh, that's quite a clean solution, I like that. Heck, no need for > Callable, we already have ->getClosure() in Reflection. A modified > version of that for constructors could work > (ReflectionClass::getConstructorClosure() ?). > > Thanks.
Hey Andrea, This would still not solve Dan's problem though. Which is representing `new Class` as a serializeable callable. I really think ::new() makes the most sense here (and looks quite alright unlike `Class::__construct()`). Although making a special case for `new ...` is pretty simple, I too have felt the need for callable constructors plenty of times, that would be useful.

Rowan Collins

10 years ago
On 26/02/2016 11:47, Nikita Nefedov wrote:
>>> Then we could add to that a special case for constructors: >>> >>> - Callable::forConstructor(string $class_name) >>> >> >> Oh, that's quite a clean solution, I like that. Heck, no need for >> Callable, we already have ->getClosure() in Reflection. A modified >> version of that for constructors could work >> (ReflectionClass::getConstructorClosure() ?). >> >> Thanks. > > Hey Andrea, > > This would still not solve Dan's problem though. Which is representing > `new Class` as a serializeable callable.
There are lots of types of callable which can't be serialized already - anonymous functions, invokable objects, instance methods - so I'm still not convinced why this particular one is so important. Anything that can only take its callback as a string already rejects many things that are otherwise callable, so I'm not sure why having to reject a wrapped constructor is so much worse that it needs a new language concept. Regards,
-- Rowan Collins [IMSoP]

Rowan Collins

10 years ago
On 26/02/2016 11:28, Andrea Faulds wrote:
>> Then we could add to that a special case for constructors: >> >> - Callable::forConstructor(string $class_name) >> > > Oh, that's quite a clean solution, I like that. Heck, no need for > Callable, we already have ->getClosure() in Reflection. A modified > version of that for constructors could work > (ReflectionClass::getConstructorClosure() ?).
Reflection always feels to me like "the language doesn't really support this, but you can sort of cheat this way", but maybe that's a poor prejudice. Regards,
-- Rowan Collins [IMSoP]

Adam Harvey

10 years ago
On 25 February 2016 at 08:44, Dan Ackroyd <danack@basereality.com> wrote:
> I use the Auryn* DIC library. What I've wanted to do, and should be > able to do in my opinion, is this: > > $injector->delegate('FooInterface', 'FooImplementation::__construct');
I only skimmed the RFC (and am unfamiliar with Auryn beyond glancing at its documentation for about ten seconds just now), but am I right that this is equivalent to the following? $injector->delegate('FooInterface', function (...$args) { return new FooImplementation(...$args); }); If that's the case, I'm not really convinced that this is worth the syntactic sugar. I'm also somewhat concerned about conflating instantiation and method calls — although they both ultimately call a method, they're not actually the same thing, since instantiating an object does extra work at the same time. Being able to just look for "new" in code is helpful. Open to being convinced otherwise (examples from other languages would be helpful), but my initial reaction isn't really positive. Thanks, Adam

Dan Ackroyd

10 years ago
On 25 February 2016 at 18:16, Adam Harvey <adam@adamharvey.name> wrote:
> > am I right > that this is equivalent to the following? > >$injector->delegate('FooInterface', function (...$args) { return new
FooImplementation(...$args); }); Nope. The vital part you missed is that with the original function, all of the parameters (aka dependencies of the class) can be found through reflection, and so can be created by the injector as needed. By using function (...$args){} - all of the parameter information is lost, and so isn't usable by an autowiring-injector. The only equivalent thing that would be to either create a dumb function by hand: function createFooImpl(Bar $bar, Quux $quux) { return new FooImplementation($bar, $quux); } for every possible constructor used in your app (and remember to keep it up to date of course!), or to use eval to create a function on the fly.
> "I only skimmed the RFC"
I find this very dissapointing. Conversations are far more productive if people have read the whole of a proposal before deciding how they feel about it and giving feedback. In particular reading the sections "Can't be used as strings in class properties" and "Can't be used in string based configuration" would give examples where the RFC is of benefit in a way that is not related to DIC libraries. cheers Dan

Adam Harvey

10 years ago
On 25 February 2016 at 14:19, Dan Ackroyd <danack@basereality.com> wrote:
> On 25 February 2016 at 18:16, Adam Harvey <adam@adamharvey.name> wrote: >> >> am I right >> that this is equivalent to the following? >> >>$injector->delegate('FooInterface', function (...$args) { return new > FooImplementation(...$args); }); > > Nope. > > The vital part you missed is that with the original function, all of > the parameters (aka dependencies of the class) can be found through > reflection, and so can be created by the injector as needed. By using > function (...$args){} - all of the parameter information is lost, and > so isn't usable by an autowiring-injector.
OK, I understand that now. Thanks. Why is having a special syntax that is considered callable and conflates instantiation and method calls (which are ultimately separate things) better than having the injector accept a class name and use reflection as required to instantiate that?
>> "I only skimmed the RFC" > > I find this very dissapointing. Conversations are far more productive > if people have read the whole of a proposal before deciding how they > feel about it and giving feedback.
To be clear: I did read the entire RFC, just quickly. Since it seemed an obvious question to me (and apparently not just me, based on /r/php), and didn't seem to be addressed that I could see, I thought it was better to just ask it rather than stay silent and either ask it several days later or vote -1 without explanation.
> In particular reading the sections "Can't be used as strings in class > properties" and "Can't be used in string based configuration" would > give examples where the RFC is of benefit in a way that is not related > to DIC libraries.
Honestly, I still don't find either of them particularly persuasive, for the same reasons as the aforementioned DIC example. They're trivially special cased without muddying instantiation and method calls. Hence my "are there analogues for this elsewhere" question. Adam

Dan Ackroyd

10 years ago
On 25 February 2016 at 22:43, Adam Harvey <aharvey@php.net> wrote:
> Why is having a special syntax that is considered callable and > conflates instantiation and method calls better than having the injector accept a class name > and use reflection as required to instantiate that? > They're > trivially special cased without muddying instantiation and method > calls. Hence my "are there analogues for this elsewhere" question.
I think this is actually something that would be useful across applications - not just my own library. Although I could use the Reflection code that Johannes wrote to make it possible for my own code to use constructors as a callable, I wouldn't be able to use it in anyone else's code, unless I asked them nicely to add the special casing to their library code as well. For example I would hope to use callable constructors with the Zend service manager. That is a good example of where just being able to specify "Foo::__construct" in a config file would save having to write 'boiler plate' instantiation functions for every object. I think there is a small 'chicken and egg' problem here. Of course no one is currently using constructors as callable, because it isn't possible yet, and so it's hard to point to any code that uses them. And so it appears that it's an small use case. I'm pretty sure if it was adopted it would become a standard thing to do when 'wiring up' applications, or hydrating objects fetched from various data sources. Rowan Wrote:
> I would like to join Adam in asking if > you can find examples in other languages where constructors can be used > as though they were static methods in this way.
Python would be a good example. constructors are just functions that can be called, and passed around as 'callable' things. Obviously Pythons concepts of classes aren't identical to PHP' concepts - but the code is doing the same thing; passing around a thing that can be called without having to use Reflection to make it a callable. http://goo.gl/SnTNZH ==== Begin from random import randint class Foo: def f(self): return 'I am foo' class Bar: def f(self): return 'I am bar' if randint(0,1) == 0: classname = Foo else: classname = Bar obj = classname() print obj.f() ==== End I'm not aware of any languages that contemplated making it be callable, but then decided it would be a bad idea. cheers Dan

Rowan Collins

10 years ago
On 26/02/2016 17:08, Dan Ackroyd wrote:
> Rowan Wrote: >> I would like to join Adam in asking if >> you can find examples in other languages where constructors can be used >> as though they were static methods in this way. > Python would be a good example. constructors are just functions that > can be called, and passed around as 'callable' things. > > Obviously Pythons concepts of classes aren't identical to PHP' > concepts - but the code is doing the same thing; passing around a > thing that can be called without having to use Reflection to make it a > callable. > > > http://goo.gl/SnTNZH
Looking at your example at first, I couldn't see how it demonstrated any such passing, because you can dynamically select class names in PHP (here's that code transposed line-by-line to PHP): https://3v4l.org/AD2m3 Looking closer, that's not actually what's happening, but it's still not equivalent to what you want in PHP: - The first difference is that "Foo()" rather than "new Foo()" creates an object; the fact that "Foo" is a class rather than a function causes this to happen when it is invoked. This is different from PHP, where classes and functions don't share a namespace, and a class is not something that can be invoked ("foo()" doesn't refer to the same thing as "new foo()"). - The second difference is that you are not passing around a string representing what to call, but a reference to the invokable object itself. The line "classname = Foo" simply makes "classname" an alias for the class "Foo", which is then invokable as before to trigger instantiation. So if anything, this particular example is more like my Callable::forConstructor() idea - a way of passing around an invokable object which, when invoked, will cause instantiation of a particular class. I don't, however, know Python well enough to say whether a better example would be more like what you want in PHP. Regards,
-- Rowan Collins [IMSoP]

Andrew Faulds

10 years ago
Hi Dan, Dan Ackroyd wrote:
> On 25 February 2016 at 18:16, Adam Harvey <adam@adamharvey.name> wrote: >> >> am I right >> that this is equivalent to the following? >> >> $injector->delegate('FooInterface', function (...$args) { return new > FooImplementation(...$args); }); > > Nope. > > The vital part you missed is that with the original function, all of > the parameters (aka dependencies of the class) can be found through > reflection, and so can be created by the injector as needed. By using > function (...$args){} - all of the parameter information is lost, and > so isn't usable by an autowiring-injector.
This is true for a trivial implementation like the one above, but I would point out that a more sophisticated userland implementation could fix this by generating PHP code. So it's still worth questioning whether this needs to be a built-in function. Thanks!
-- Andrea Faulds https://ajf.me/

Johannes Schlueter

10 years ago
On Fri, 2016-02-26 at 11:30 +0000, Andrea Faulds wrote:
> This is true for a trivial implementation like the one above, but I > would point out that a more sophisticated userland implementation could > fix this by generating PHP code.
You don't have to generate PHP code for this to work: $arr = is_string($func) ? explode("::", $func, 2) : $func; $ref = (sizeof($arr) === 2) ? new ReflectionMethod($arr[0], $arr[1]) : new ReflectionFunction($func); $args = identifyArgumentsAndGetCtorArgs($ref); if (sizeof($arr) === 2 && $arr[1] === '__construct') { $rc = new ReflectionClass($arr[0]); return $rc->newInstanceArgs($args); } else { return $ref->invokeArgs($args); } I haven't tested this and it might need some fine tuning, but isn't really complicated. (Of course you can generate PHP code for this trivially in order to avoid the small reflection overhead)
> So it's still worth questioning whether this needs to be a built-in > function.
I think it is quite obscure and a hardly used feature. Language features and syntax sugar things should be common things. johannes

Marco Pivetta

10 years ago
Just adding to the use-cases: I really could've needed this the other day: $records = array_map([MyRecord::class, '__construct'], $db->someQuery()->fetchAll()); I used a named constructor instead, but this results with more internal method calls: $records = array_map([MyRecord::class, 'fromResultSetRow'], $db->someQuery()->fetchAll()); So yeah, I see some clear advantages in making constructors (static by design) available statically. Marco Pivetta http://twitter.com/Ocramius http://ocramius.github.com/ On 25 February 2016 at 11:44, Dan Ackroyd <danack@basereality.com> wrote:

Ryan Pallas

10 years ago
On Thu, Feb 25, 2016 at 11:20 AM, Marco Pivetta <ocramius@gmail.com> wrote:
> Just adding to the use-cases: I really could've needed this the other day: > > > $records = array_map([MyRecord::class, '__construct'], > $db->someQuery()->fetchAll()); > > I used a named constructor instead, but this results with more internal > method calls: > > $records = array_map([MyRecord::class, 'fromResultSetRow'], > $db->someQuery()->fetchAll()); >
If fetchAll is coming from PDO. then you could have simply done this: $records = $db->someQuery()->fetchAll(MyRecord::class);

Marco Pivetta

10 years ago
On 25 February 2016 at 13:31, Ryan Pallas <derokorian@gmail.com> wrote:
> > > On Thu, Feb 25, 2016 at 11:20 AM, Marco Pivetta <ocramius@gmail.com> > wrote: > >> Just adding to the use-cases: I really could've needed this the other day: >> >> >> $records = array_map([MyRecord::class, '__construct'], >> $db->someQuery()->fetchAll()); >> >> I used a named constructor instead, but this results with more internal >> method calls: >> >> $records = array_map([MyRecord::class, 'fromResultSetRow'], >> $db->someQuery()->fetchAll()); >> > > If fetchAll is coming from PDO. then you could have simply done this: > > $records = $db->someQuery()->fetchAll(MyRecord::class); >
Not using PDO there. Marco Pivetta http://twitter.com/Ocramius http://ocramius.github.com/

Ryan Pallas

10 years ago
On Thu, Feb 25, 2016 at 11:31 AM, Ryan Pallas <derokorian@gmail.com> wrote:
> > > On Thu, Feb 25, 2016 at 11:20 AM, Marco Pivetta <ocramius@gmail.com> > wrote: > >> Just adding to the use-cases: I really could've needed this the other day: >> >> >> $records = array_map([MyRecord::class, '__construct'], >> $db->someQuery()->fetchAll()); >> >> I used a named constructor instead, but this results with more internal >> method calls: >> >> $records = array_map([MyRecord::class, 'fromResultSetRow'], >> $db->someQuery()->fetchAll()); >> > > If fetchAll is coming from PDO. then you could have simply done this: > > $records = $db->someQuery()->fetchAll(MyRecord::class); >
Sorry, that should have been $records = $db->someQuery()->fetchAll(PDO::FETCH_CLASS, $MyRecord::class);

Dan Ackroyd

10 years ago
On 25 February 2016 at 18:32, Ryan Pallas <derokorian@gmail.com> wrote:
> If fetchAll is coming from PDO. then you could have simply done this: > > $records = $db->someQuery()->fetchAll(MyRecord::class);
That is a great argument as to why constructors should be callable without using the 'new'. It's been possible to do that in PDO for years, and people have been using it, and liking it, even if they weren't aware that 'under the hood' the PDO extension was doing the equivalent of calling 'new' as a callable. But why is it restricted to PDO? Why can't I do the equivalent with other DB libraries of my choice? Why can't I use it with userland libraries that retrieve data from Redis, Mongo or any other datasource? It has shown to be a useful pattern inside PDO. We should be empowering userland developers to have the same tools available to them as extensions do, wherever possible. This RFC would allow the equivalent of PDO::FETCH_CLASS to be implemented by userland code. Which sounds great to me.
> Moreover, if you want to pass in a callable that creates the class, why not > just create a method on that class called create (or whatever) much the > same way that singletons often work.
Why should every PHP developer have to jump through that hoop, why can't we (as the RFC proposes) make constructors be callable, instead of having to create another method just to call something that should have been callable in the first place? And to be precise, people need to use code that was either written outside their organisation, or within their organisation but in another department. In either case it wouldn't be possible to alter the code just to make it callable in a certain way. And so it would be easier if the language just supported something that could have been supported right from the start. cheers Dan

Rowan Collins

10 years ago
On 25/02/2016 22:11, Dan Ackroyd wrote:
> It's been possible to do that in PDO for years, and people have been > using it, and liking it, even if they weren't aware that 'under the > hood' the PDO extension was doing the equivalent of calling 'new' as a > callable.
Actually, PDO_FETCH_CLASS does something rather magic: it creates an object and actually injects individual property values into it. The constructor is not being used as a callback at all, and by default is called (with no parameters) *after* the properties have been initialised (a rather odd sequence, but there you go).
> But why is it restricted to PDO? Why can't I do the equivalent with > other DB libraries of my choice? Why can't I use it with userland > libraries that retrieve data from Redis, Mongo or any other > datasource? > > It has shown to be a useful pattern inside PDO. We should be > empowering userland developers to have the same tools available to > them as extensions do, wherever possible.
What exactly is stopping you doing it right now? Note that PDO has code written specifically for this case, which takes a class name and uses it in a particular way; if all it was doing was calling the constructor of that class, it would be trivial to implement in userland code: "new $classname($args)" works just fine, AFAIK. The only part that is not possible right now - in PDO or anywhere else in the language - is to pass the constructor directly to a context that's expecting a callable. You have demonstrated some use cases where that would be convenient, but all of them can be implemented a different way reasonably easily.
> Why should every PHP developer have to jump through that hoop, why > can't we (as the RFC proposes) make constructors be callable, instead > of having to create another method just to call something that should > have been callable in the first place?
You talk of "jumping through hoops" and "should have been ... in the first place" as though it is self-evident that calling a constructor statically should imply object creation. A constructor is not a static method that somehow creates a new instance; rather, the "new" keyword is what creates the instance, and the constructor is an instance method called *after* creation, but before returning the new object to the caller. It's important to remember that constructors and the "new" keyword are not concepts that PHP invented. I would like to join Adam in asking if you can find examples in other languages where constructors can be used as though they were static methods in this way. While there's nothing wrong with PHP being the only language to do something, there may be sound theory behind how other languages work. Regards,
-- Rowan Collins [IMSoP]

Ryan Pallas

10 years ago
On Thu, Feb 25, 2016 at 9:44 AM, Dan Ackroyd <danack@basereality.com> wrote:
> Hello internals, > > I've written a small RFC to make it possible to call constructors of > objects as a callable, rather than only being able to call them > through the 'new' language construct. > > https://wiki.php.net/rfc/callableconstructors > > After gathering informal feedback for the RFC, one person said that > they felt it needed more of an emphasis on why it should be > implemented. I wanted to keep the actual RFC short, in the hope that > more people would read it in it's entirety, and also wanted to leave > library specific code out of the RFC. So, as an addendum to the RFC > text: > > I use the Auryn* DIC library. What I've wanted to do, and should be > able to do in my opinion, is this: > > $injector->delegate('FooInterface', 'FooImplementation::__construct');
> Which tells the injector "Whenever something requests an object that > implements FooInterface as a dependency, just execute the > FooImplementation constructor to make that object". >
How is this any better, or what benefit would it provide over the current implementation, which takes a class name and then calls new on it when the Interface is asked for? Moreover, if you want to pass in a callable that creates the class, why not just create a method on that class called create (or whatever) much the same way that singletons often work.

Stas Malyshev

10 years ago
Hi!
> If constructors had always been callable in PHP, this would be a > standard thing to do and not controversial imo. It's only due to > reasons lost in the mists of time, that object instantiation can only > be invoked via 'new' that it's not possible currently, and so needs an > RFC to change.
Constructors have always been callable in PHP and still are. They are functions like any other. What you need is a factory method, not a constructor - constructor is called to initialize object, not create it. But you can create factory methods at will, you just don't have to call it __construct.
-- Stas Malyshev smalyshev@gmail.com