Currently, class name resolution supports all types except an array.
https://3v4l.org/OXFMW
In fact, it is syntactically invalid since the parser fails to recognize
array::class
as an array expression:
Parse error: syntax error, unexpected 'array' (T_ARRAY), expecting
identifier (T_STRING)
https://3v4l.org/5IOoI
Is possible to change the grammar to support array also?
- Marcos
Since array
is not a class, it doesn't make sense to resolve its type.
What's the use-case for such pseudo-constant in your code?
Marco Pivetta
On Mon, Oct 1, 2018 at 1:30 AM Marcos Passos marcospassos.com@gmail.com
wrote:
Currently, class name resolution supports all types except an array.
https://3v4l.org/OXFMWIn fact, it is syntactically invalid since the parser fails to recognize
array::class
as an array expression:Parse error: syntax error, unexpected 'array' (T_ARRAY), expecting
identifier (T_STRING)
https://3v4l.org/5IOoIIs possible to change the grammar to support array also?
- Marcos
On Mon, 1 Oct 2018 at 00:30, Marcos Passos marcospassos.com@gmail.com
wrote:
Currently, class name resolution supports all types except an array.
https://3v4l.org/OXFMW
It seems to me that the bug is allowing an expression like "int::class" to
resolve, when "int" is no longer a legal class name.
I suspect the reason "array::class" doesn't work is that it was already a
reserved word in PHP 5, whereas other types were legal class names. In PHP
5, "int::class" can plausibly resolve to the name of an actual class, but
in PHP 7, it can't, but clearly this part of the grammar wasn't updated to
reflect that.
The parser is being too forgiving here, I think, and should complain if the
word before :: is not a valid class name.
Regards,
Rowan Collins
[IMSoP]
Rowan, thank you for sharing your thoughts.
You can also see it as a language construct that expects a type at the
left-hand side of the name resolution operator. In that sense, primitive
types are perfectly valid.
Regards,
Marcos
Em seg, 1 de out de 2018 às 05:45, Rowan Collins rowan.collins@gmail.com
escreveu:
On Mon, 1 Oct 2018 at 00:30, Marcos Passos marcospassos.com@gmail.com
wrote:Currently, class name resolution supports all types except an array.
https://3v4l.org/OXFMWIt seems to me that the bug is allowing an expression like "int::class" to
resolve, when "int" is no longer a legal class name.I suspect the reason "array::class" doesn't work is that it was already a
reserved word in PHP 5, whereas other types were legal class names. In PHP
5, "int::class" can plausibly resolve to the name of an actual class, but
in PHP 7, it can't, but clearly this part of the grammar wasn't updated to
reflect that.The parser is being too forgiving here, I think, and should complain if
the word before :: is not a valid class name.Regards,
Rowan Collins
[IMSoP]
They are still not classes
Rowan, thank you for sharing your thoughts.
You can also see it as a language construct that expects a type at the
left-hand side of the name resolution operator. In that sense, primitive
types are perfectly valid.Regards,
MarcosEm seg, 1 de out de 2018 às 05:45, Rowan Collins rowan.collins@gmail.com
escreveu:On Mon, 1 Oct 2018 at 00:30, Marcos Passos marcospassos.com@gmail.com
wrote:Currently, class name resolution supports all types except an array.
https://3v4l.org/OXFMWIt seems to me that the bug is allowing an expression like "int::class"
to
resolve, when "int" is no longer a legal class name.I suspect the reason "array::class" doesn't work is that it was already a
reserved word in PHP 5, whereas other types were legal class names. In
PHP
5, "int::class" can plausibly resolve to the name of an actual class, but
in PHP 7, it can't, but clearly this part of the grammar wasn't updated
to
reflect that.The parser is being too forgiving here, I think, and should complain if
the word before :: is not a valid class name.Regards,
Rowan Collins
[IMSoP]
On Mon, 1 Oct 2018 at 13:24, Marcos Passos marcospassos.com@gmail.com
wrote:
You can also see it as a language construct that expects a type at the
left-hand side of the name resolution operator. In that sense, primitive
types are perfectly valid.
While I can see that as an interpretation, it doesn't make a lot of sense:
- the keyword "class" implies that this will always return a class name; it
is the static equivalent ofget_class()
, which does not support non-objects - if instead it was resolving a "type", you might expect it to return the
same values asgettype()
, which for any object is simply the string "object" - the main purpose of the feature is to resolve namespace lookups and
aliases, but basic types are not subject to namespaces; in other words,
"int::class" can only ever return "int"
As Marco says, if you have a use case where allowing this is helpful,
please share it, and we can discuss if this, or some new related feature
(e.g. "array::type"), would be worth supporting.
Regards,
Rowan Collins
[IMSoP]
Sorry, it looks like I've replied to Marco only.
About use case, we use it to specify types in standardized fashion:
if (!$value instanceof Foo) {
throw InvalidArgumentException::unexpectedType($value, Foo::class);
}
if (!\is_int($value)) {
throw new InvalidArgumentException::unexpectedType($value,
\int::class);
}$converter->convert($value, \int::class);
I also said that it might have some benefits for generic types:
I don't disagree with you, but it's already supported right now, so what
I'm only proposing to make it consistent.
Looking forward, supporting name resolution for primitive may have some
benefits for generic types
https://github.com/PHPGenerics/php-generics-rfc/issues/20#issuecomment-407600337
.
Beside this, deprecating it now would represent a BC break, right?
Em seg, 1 de out de 2018 às 10:15, Rowan Collins rowan.collins@gmail.com
escreveu:
On Mon, 1 Oct 2018 at 13:24, Marcos Passos marcospassos.com@gmail.com
wrote:You can also see it as a language construct that expects a type at the
left-hand side of the name resolution operator. In that sense, primitive
types are perfectly valid.While I can see that as an interpretation, it doesn't make a lot of sense:
- the keyword "class" implies that this will always return a class name;
it is the static equivalent ofget_class()
, which does not support
non-objects- if instead it was resolving a "type", you might expect it to return the
same values asgettype()
, which for any object is simply the string "object"- the main purpose of the feature is to resolve namespace lookups and
aliases, but basic types are not subject to namespaces; in other words,
"int::class" can only ever return "int"As Marco says, if you have a use case where allowing this is helpful,
please share it, and we can discuss if this, or some new related feature
(e.g. "array::type"), would be worth supporting.Regards,
Rowan Collins
[IMSoP]
On Mon, 1 Oct 2018 at 14:30, Marcos Passos marcospassos.com@gmail.com
wrote:
Sorry, it looks like I've replied to Marco only.
About use case, we use it to specify types in standardized fashion:
if (!$value instanceof Foo) {
throw InvalidArgumentException::unexpectedType($value, Foo::class);
}
if (!\is_int($value)) {
throw new InvalidArgumentException::unexpectedType($value,
\int::class);
}$converter->convert($value, \int::class);
This is just obfuscation for no gain, IMO:
- \int::class is 6 characters longer than 'int', and guaranteed to have the
same value. - It doesn't protect against typos like a constant would, because
\itn::class will reliably and silently resolve to 'itn' whether or not such
a class exists. - It implies that "int" is a class, which it is not; and that the methods
always take a class name, which they do not.
I also said that it might have some benefits for generic types:
I don't disagree with you, but it's already supported right now, so what
I'm only proposing to make it consistent.
Looking forward, supporting name resolution for primitive may have some
benefits for generic types
https://github.com/PHPGenerics/php-generics-rfc/issues/20#issuecomment-407600337
.
I note that in that discussion, the suggestion of ::type has already come
up, and given its own thread:
https://github.com/PHPGenerics/php-generics-rfc/issues/27
In my view, that would make more sense than officially supporting "::class"
for things other than classes.
Beside this, deprecating it now would represent a BC break, right?
Nit-pick: deprecation is never a BC break; it just implies eventual
removal, which is.
But yes, outright banning it now would be a BC break. IMO it should have
been banned at the same time "int", "string", etc were made illegal class
names (in PHP 7.0), but I can see an argument that our next chance is PHP
8.0.
I still think removing it is the right thing to do, however; it only works
by mistake, as demonstrated by array::class not being supported when the
feature was first added.
Regards,
Rowan Collins
[IMSoP]
- It doesn't protect against typos like a constant would, because
\itn::class will reliably and silently resolve to 'itn' whether or not such
a class exists.
It's a good point, I didn't realized that.
Having a ::type pseudo-constant is preferable, indeed. The whole point was
about making it consistent before you stated that this use case become
valid by mistake.
Em seg, 1 de out de 2018 às 10:52, Rowan Collins rowan.collins@gmail.com
escreveu:
On Mon, 1 Oct 2018 at 14:30, Marcos Passos marcospassos.com@gmail.com
wrote:Sorry, it looks like I've replied to Marco only.
About use case, we use it to specify types in standardized fashion:
if (!$value instanceof Foo) {
throw InvalidArgumentException::unexpectedType($value, Foo::class);
}
if (!\is_int($value)) {
throw new InvalidArgumentException::unexpectedType($value,
\int::class);
}$converter->convert($value, \int::class);
This is just obfuscation for no gain, IMO:
- \int::class is 6 characters longer than 'int', and guaranteed to have
the same value.- It doesn't protect against typos like a constant would, because
\itn::class will reliably and silently resolve to 'itn' whether or not such
a class exists.- It implies that "int" is a class, which it is not; and that the methods
always take a class name, which they do not.I also said that it might have some benefits for generic types:
I don't disagree with you, but it's already supported right now, so what
I'm only proposing to make it consistent.
Looking forward, supporting name resolution for primitive may have some
benefits for generic types
https://github.com/PHPGenerics/php-generics-rfc/issues/20#issuecomment-407600337
.I note that in that discussion, the suggestion of ::type has already come
up, and given its own thread:
https://github.com/PHPGenerics/php-generics-rfc/issues/27In my view, that would make more sense than officially supporting
"::class" for things other than classes.Beside this, deprecating it now would represent a BC break, right?
Nit-pick: deprecation is never a BC break; it just implies eventual
removal, which is.But yes, outright banning it now would be a BC break. IMO it should have
been banned at the same time "int", "string", etc were made illegal class
names (in PHP 7.0), but I can see an argument that our next chance is PHP
8.0.I still think removing it is the right thing to do, however; it only works
by mistake, as demonstrated by array::class not being supported when the
feature was first added.Regards,
Rowan Collins
[IMSoP]