Hi!
The point is here:
https://gist.github.com/vhood/665418835e65be26d5a818fded92ab75
Is it possible? May I create an RFC for this?
Hi Viktor,
On Mon, Feb 17, 2025 at 4:42 PM Viktor Khramov dev.999.victor@gmail.com
wrote:
Hi!
The point is here:
https://gist.github.com/vhood/665418835e65be26d5a818fded92ab75Is it possible? May I create an RFC for this?
Already possible like this:
class Decision
{
#[Main]
public function __construct(
private readonly Uuid $id,
private readonly string $comment,
) {
}
public static function fromEmail(string $mailSubject, string
$mailBody): static
{
$id = preg_replace('/pattern/', "$1", $mailSubject);
$comment = preg_replace('/pattern/', "$1", $mailBody);
return new static(
id: new Uuid($id),
comment: $comment,
);
}
}
Related to overloading, that is binding to the correct function in Java/C#
at compile time, and IMO is not matching with the dynamic nature of PHP.
I think we're not losing much by not having this feature in PHP, but feel
free to think more about what the implementation would look like.
-- Alex
Hi
Related to overloading, that is binding to the correct function in
Java/C#
at compile time, and IMO is not matching with the dynamic nature of
PHP.
Indeed. See: https://github.com/php/php-src/issues/17813
Best regards
Tim Düsterhus
Hi!
The point is here:
https://gist.github.com/vhood/665418835e65be26d5a818fded92ab75
Static functions look awful and break the object's API.
Personally, I think quite the opposite: named constructors make a lot more sense than type-based overloads. For instance, you might have both createFromJson and createFromYaml; their inputs are both going to be "string" as far as the type system is concerned, so overloading would be useless.
Swift gets around this using "argument labels" which is sort of like requiring named arguments and despatching based on those names, but I believe is actually derived from SmallTalk's multipart method names.
Delphi is more explicit: a constructor is any class method marked with "constructor" in its declaration, and the name "Create" is just a convention. It does also support overloading on types, so other names are rarely used, which is a shame.
In your example, instead of this meaning different things based on what $a happens to hold:
$decision = new Decision($a, $b);
You could write one of these to be clear:
$decision = Decision::createFromId($a, $b);
$decision = Decision::createFromMail($a, $b);
Even if someone were to come up with a working implementation of overloading in PHP's type system, I would probably oppose it, because I think it makes code harder to read and reason about.
Regards,
Rowan Tommins
[IMSoP]
Decision::createFromId($uuid, $comment);
Decision::createFromMail($subject, $body);
Decision::createFromSome($a, $b, $c);
Decision::createFromAnother($a);
This doesn't look like constructors. It will be hard to read the
class, it will take time to come up with a name, it's not right. I
have different colors for functions and magic methods in my IDE,
__construct is always in focus.
new Decision($uuid, $comment);
new Decision($subject, $body);
This makes it much easier to quickly understand what is going on.
вт, 18 февр. 2025 г. в 11:03, Rowan Tommins [IMSoP] imsop.php@rwec.co.uk:
Hi!
The point is here:
https://gist.github.com/vhood/665418835e65be26d5a818fded92ab75Static functions look awful and break the object's API.
Personally, I think quite the opposite: named constructors make a lot more sense than type-based overloads. For instance, you might have both createFromJson and createFromYaml; their inputs are both going to be "string" as far as the type system is concerned, so overloading would be useless.
Swift gets around this using "argument labels" which is sort of like requiring named arguments and despatching based on those names, but I believe is actually derived from SmallTalk's multipart method names.
Delphi is more explicit: a constructor is any class method marked with "constructor" in its declaration, and the name "Create" is just a convention. It does also support overloading on types, so other names are rarely used, which is a shame.
In your example, instead of this meaning different things based on what $a happens to hold:
$decision = new Decision($a, $b);
You could write one of these to be clear:
$decision = Decision::createFromId($a, $b);
$decision = Decision::createFromMail($a, $b);Even if someone were to come up with a working implementation of overloading in PHP's type system, I would probably oppose it, because I think it makes code harder to read and reason about.
Regards,
Rowan Tommins
[IMSoP]
On Tue, Feb 18, 2025 at 10:27 AM Viktor Khramov dev.999.victor@gmail.com
wrote:
Decision::createFromId($uuid, $comment);
Decision::createFromMail($subject, $body);
Decision::createFromSome($a, $b, $c);
Decision::createFromAnother($a);This doesn't look like constructors. It will be hard to read the
class, it will take time to come up with a name, it's not right. I
have different colors for functions and magic methods in my IDE,
__construct is always in focus.new Decision($uuid, $comment);
new Decision($subject, $body);This makes it much easier to quickly understand what is going on.
вт, 18 февр. 2025 г. в 11:03, Rowan Tommins [IMSoP] <imsop.php@rwec.co.uk
:
On 17 February 2025 14:39:42 GMT, Viktor Khramov <
dev.999.victor@gmail.com> wrote:Hi!
The point is here:
https://gist.github.com/vhood/665418835e65be26d5a818fded92ab75Static functions look awful and break the object's API.
Personally, I think quite the opposite: named constructors make a lot
more sense than type-based overloads. For instance, you might have both
createFromJson and createFromYaml; their inputs are both going to be
"string" as far as the type system is concerned, so overloading would be
useless.Swift gets around this using "argument labels" which is sort of like
requiring named arguments and despatching based on those names, but I
believe is actually derived from SmallTalk's multipart method names.Delphi is more explicit: a constructor is any class method marked with
"constructor" in its declaration, and the name "Create" is just a
convention. It does also support overloading on types, so other names are
rarely used, which is a shame.In your example, instead of this meaning different things based on what
$a happens to hold:$decision = new Decision($a, $b);
You could write one of these to be clear:
$decision = Decision::createFromId($a, $b);
$decision = Decision::createFromMail($a, $b);Even if someone were to come up with a working implementation of
overloading in PHP's type system, I would probably oppose it, because I
think it makes code harder to read and reason about.Regards,
Rowan Tommins
[IMSoP]
My only "issue" with static constructors is that it's unclear what you can
do, especially if you mix constructors with static constructors. Typing
"new TheClass" in PhpStorm for example won't show if the constructor is
protected/private based on the scope, and won't show all possible
constructors. On the other hand if type TheClass::
PhpStorm won't show
you the normal constructor and none at all if you don't have any static
functions. I don't know if there's a good solution to this problem though.
Could look into:
-
[#Constructor]
attributes - allowing "constructor" instead of "function" when defining the function
- these possibly have more benefits such as with-ers and non-static
factory methods on other objects
While I'd love to have a better way to quickly know what functions are
constructors, I don't know if this is something that should be solved in
the language.
Am 18.02.2025 um 09:00 schrieb Rowan Tommins [IMSoP]:
named constructors make a lot more sense than type-based overloads
+1
Am 18.02.2025 um 09:00 schrieb Rowan Tommins [IMSoP]:
named constructors make a lot more sense than type-based overloads
+1
Hi, Viktor.
I agree with others that named static constructors are much better
than overloading
of the primary constructor. Regardless of whether it is possible in PHP or
not.
Even for Java that supports overloading, Robert Martin recommends factory
methods in his book "Clean code": "Prefer static factory methods (with
names that describe the arguments) to overloaded constructors."
Also see this discussion:
https://stackoverflow.com/questions/628950/constructors-vs-factory-methods
--
Valentin
Hi
Am 2025-02-18 09:00, schrieb Rowan Tommins [IMSoP]:
Personally, I think quite the opposite: named constructors make a lot
more sense than type-based overloads. For instance, you might have both
createFromJson and createFromYaml; their inputs are both going to be
"string" as far as the type system is concerned, so overloading would
be useless.
To add an example from PHP’s standard library: The new DOM API shipped
in PHP 8.4 uses named constructors to create documents and requires this
to distinguish between createFromFile
and createFromString
.
final class HTMLDocument extends Document
{
public static function createEmpty(string $encoding = "UTF-8"):
HTMLDocument {}
public static function createFromFile(string $path, int $options
= 0, ?string $overrideEncoding = null): HTMLDocument {}
public static function createFromString(string $source, int
$options = 0, ?string $overrideEncoding = null): HTMLDocument {}
// […]
}
Best regards
Tim Düsterhus
On 17 February 2025 14:39:42 GMT, Viktor Khramov
dev.999.victor@gmail.com wrote:Hi!
The point is here:
https://gist.github.com/vhood/665418835e65be26d5a818fded92ab75Static functions look awful and break the object's API.
Personally, I think quite the opposite: named constructors make a lot
more sense than type-based overloads. For instance, you might have both
createFromJson and createFromYaml; their inputs are both going to be
"string" as far as the type system is concerned, so overloading would
be useless.Swift gets around this using "argument labels" which is sort of like
requiring named arguments and despatching based on those names, but I
believe is actually derived from SmallTalk's multipart method names.Delphi is more explicit: a constructor is any class method marked with
"constructor" in its declaration, and the name "Create" is just a
convention. It does also support overloading on types, so other names
are rarely used, which is a shame.In your example, instead of this meaning different things based on what
$a happens to hold:$decision = new Decision($a, $b);
You could write one of these to be clear:
$decision = Decision::createFromId($a, $b);
$decision = Decision::createFromMail($a, $b);Even if someone were to come up with a working implementation of
overloading in PHP's type system, I would probably oppose it, because I
think it makes code harder to read and reason about.
I largely agree. I am open to method overloading as a general feature (which is probably the minority view around here), as I do see places it would be helpful. (Enum methods, operator overloads if those ever happen, etc.) But constructors feel like the least applicable place for them, and named static methods works just fine in my experience.
--Larry Garfield