|
php.net | support | documentation | report a bug | advanced search | search howto | statistics | random bug | login |
[2016-01-20 13:06 UTC] andreas at dqxtech dot net
Description: ------------ I often create classes that have a normal constructor, and one or more static factory methods. On instantiation, I need to decide between "new C()" and "C::create()". For method chaining, the "new C()" needs additional brackets, like so: "(new C())". Switching between the two notations can be annoying. Proposal: Allow a syntax "C::new()", which would be equivalent to "(new C())". -------- Now.. when I had this idea, I was not aware that since PHP 7, and also in hhvm, it is possible to name a method like "new()". https://3v4l.org/Pp68v with user-defined method new(). https://3v4l.org/YvjJ9 without such a method. This is unfortunate, and makes this request difficult, if not impossible. A remaining (but not really great) option would be to give every class an "implicit" static method ::new(), but allow this method to be overridden. Maybe this was already discussed and discarded, and this is the reason why a method named "new()" is now allowed. In this case I would like this to be considered a support request. The answer could be a link to the discussion where this was decided. Test script: --------------- <?php class C {} class D { /** * Allowed since PHP 7 */ static function new() {return NULL;} } // Call implicit method new, equivalent to "new C()"; $instance = C::new(); assert($instance instanceof C); // Call explicit method new. $null = D::new(); assert($null === null); PatchesPull RequestsHistoryAllCommentsChangesGit/SVN commits
|
|||||||||||||||||||||||||||||||||
Copyright © 2001-2025 The PHP GroupAll rights reserved. |
Last updated: Sun Nov 02 12:00:01 2025 UTC |
@marcio ::new() would always have the same signature as the constructor. It would implictly call the constructor. C::new($x, $y, $z) would be equivalent with (new C($x, $y, $z)). So, I think the problem you see does not exist. On the other hand, we have to ask if method_exists('C', 'new') would return TRUE or FALSE. And what ReflectionClass would say about the pseudo-method "new". And yes, if we see it as a method, then it would break the Liskov substitution principle - if we say it applies to static methods at all. So maybe the easiest would be to immediately let the interpreter translate C::new() to (new C()), and never treat it as a method. And what about is_callable(['C', 'new']) ? This shows both a problem and an opportunity. Passing a ['C', 'new'] around like any regular callback would be quite powerful, because it would unify factory callbacks. But it also means special casing and discussion for a number of core functions/functionality like method_exists(), is_callable(), and reflection. > So far this is what I've been questioning: > > - Would ::new() always instantiate an empty (and useless) ImmutableArray? No. ImmutableArray::new() will trigger a "Warning: Missing argument 1 for ImmutableArray::__construct()". > - Would it be necessary to implement ::new() to ::new(array $data) so it follows the same spec of __construct(array $data)? No. The implicit pseudo-method ::new() already has the signature of the constructor. - Would we be able to overwrite ::new() at all? Before PHP 7, I would have said that "new" is a reserved word, and cannot be used as a method name. C::new($x) always means (new C($x)), and triggers the constructor. Hence, if you overwrite the constructor, you have implicitly overwritten the pseudo-method "::new()". Now with PHP 7 out, methods with the name new() are allowed to exist. The only language design option that does not break existing PHP 7 code would be to say that C::new($x) means (new C($x)), *unless* a real method C::new() exists, in which case this method is called instead. But people can still use the old "new C()" syntax to avoid calling the existing static method. On the positive side, this allows to add a "public static function new()", without having to change calling code - if all this calling code is already using the ::new() syntax.@marcio ::new() would always have the same signature as the constructor. It would implictly call the constructor. C::new($x, $y, $z) would be equivalent with (new C($x, $y, $z)). So, I think the problem you see does not exist. On the other hand, we have to ask if method_exists('C', 'new') would return TRUE or FALSE. And what ReflectionClass would say about the pseudo-method "new". And yes, if we see it as a method, then it would break the Liskov substitution principle - if we say it applies to static methods at all. So maybe the easiest would be to immediately let the interpreter translate C::new() to (new C()), and never treat it as a method. And what about is_callable(['C', 'new']) ? This shows both a problem and an opportunity. Passing a ['C', 'new'] around like any regular callback would be quite powerful, because it would unify factory callbacks. But it also means special casing and discussion for a number of core functions/functionality like method_exists(), is_callable(), and reflection. > So far this is what I've been questioning: > > - Would ::new() always instantiate an empty (and useless) ImmutableArray? No. ImmutableArray::new() will trigger a "Warning: Missing argument 1 for ImmutableArray::__construct()". > - Would it be necessary to implement ::new() to ::new(array $data) so it follows the same spec of __construct(array $data)? No. The implicit pseudo-method ::new() already has the signature of the constructor. - Would we be able to overwrite ::new() at all? Before PHP 7, I would have said that "new" is a reserved word, and cannot be used as a method name. C::new($x) always means (new C($x)), and triggers the constructor. Hence, if you overwrite the constructor, you have implicitly overwritten the pseudo-method "::new()". Now with PHP 7 out, methods with the name new() are allowed to exist. The only language design option that does not break existing PHP 7 code would be to say that C::new($x) means (new C($x)), *unless* a real method C::new() exists, in which case this method is called instead. But people can still use the old "new C()" syntax to avoid calling the existing static method. On the positive side, this allows to add a "public static function new()", without having to change calling code - if all this calling code is already using the ::new() syntax.