Add support for ::class to constant()

php.internals

Kévin Dunglas

5 years ago
Hi folks, Currently, it's not possible to use the ::class special constant with the constant() function. This doesn't work: var_dump( constant('\DateTime::class') ); For instance, Twig's constant() helper internally uses this PHP function, consequently the following Twig template doesn't work: `myObject` contains a random object, retrieve its class: {{ constant('class', myObject) }} I wrote a patch adding support for ::class: https://github.com/php/php-src/pull/6763 As this probably qualifies as a new feature, should I write an RFC too? Cheers,

Kamil Tekiela

5 years ago
Hi Kévin, My opinion is that you should write an RFC. I have to admit I was a little confused when I initially read your email, because I never considered ::class to be a constant. It is a special constant, which is described as a keyword in the manual. If I understand it correctly the value is obtained either at compile-time or at runtime. I would certainly want to see more explanation for your proposal with all edge cases listed out. Sounds interesting and I am looking forward to more information. Regards, Kamil

Rowan Collins

5 years ago
On 9 March 2021 22:15:49 GMT, "Kévin Dunglas" <kevin@dunglas.fr> wrote:
>Hi folks, > >Currently, it's not possible to use the ::class special constant with >the >constant() function. This doesn't work: > >var_dump( > constant('\DateTime::class') >);
While this looks logical at first glance, I'm not sure this can actually work, because you are asking at runtime for information which only exists at compile time. This is similar to other "magic" constants such as __LINE__. The only cases where ::class is calculated at runtime are self::class, and the recently added $obj::class, where $obj is an object instance. All other uses are expanded by the compiler based on the namespace and use statements in effect at that point in the code. If you try to calculate it at runtime, it would end up being evaluated where the call to constant() happens, which wouldn't actually have those namespace and use directives in effect. Consider this example: namespace Acme\Foo { use Some\Other\Baz; function test(string $class) { echo constant($class . '::class'); } } namespace Acme\Different { use Acme\Bar\Baz as BarBaz; echo Baz::class, PHP_EOL; echo BarBaz::class, PHP_EOL; echo test('Baz'); echo test('BarBaz'); } Logically, the calls to test() should result in the same output as the direct use of "::class", but the call to constant() is in a different namespace, with different use statements. I'm not sure if use statements are even available at runtime, but if they were, there would be no way of knowing that the context of the call to test() should be used, not the context where it's defined. Regards, Hi Kevin,
-- Rowan Tommins [IMSoP]

Nikita Popov

5 years ago
On Tue, Mar 9, 2021 at 11:16 PM Kévin Dunglas <kevin@dunglas.fr> wrote:
> Hi folks, > > Currently, it's not possible to use the ::class special constant with the > constant() function. This doesn't work: > > var_dump( > constant('\DateTime::class') > ); > > For instance, Twig's constant() helper internally uses this PHP function, > consequently the following Twig template doesn't work: > > `myObject` contains a random object, retrieve its class: > {{ constant('class', myObject) }} > > I wrote a patch adding support for ::class: > https://github.com/php/php-src/pull/6763 > As this probably qualifies as a new feature, should I write an RFC too? >
I'm not a fan of this change. X::class is not a constant, it just happens to share the same syntax. I think that https://github.com/php/php-src/pull/6763#issuecomment-795046502 makes the key point that if this is treated as a proper class constant in constant(), then it should also be treated as such everywhere else, including reflection. And I really don't think we want to do that. Regards, Nikita