Attributes and strict types

php.internals

Nikita Popov

5 years ago
Hi internals, I would like to clarify how attributes are supposed to interact with strict_types. Consider the following code, split up into three files to make it clear that each one could have their own strict_types mode: MyAttribute.php <?php #[Attribute] class MyAttribute { public function __construct(string $a) {} } UseOfMyAttribute.php <?php declare(strict_types=1); #[MyAttribute(42)] class Test {} AccessOfAttribute.php <?php var_dump((new ReflectionClass(Test::class'))->getAttributes()[0]->newInstance()); Currently, what happens is that this code will construct the attribute, converting int 42 into string "42", even though UseOfMyAttribute.php has strict_types=1. My intuitive expectation here would be that we should be following the strict_types mode of wherever the attribute is being used (i.e. UseOfMyAttribute.php, not MyAttribute.php or AccessOfAttribute.php). Currently, we always assume strict_types=0. Is my expectation correct? Regards, Nikita

Brent

5 years ago
Hi Nikita From a userland point of view, I'd indeed expect this example to use strict_types, because it's declared in UseOfMyAttribute.php. Is this something that can be changed still? Kind regards Brent

Larry Garfield

5 years ago
On Tue, Sep 22, 2020, at 7:58 AM, Nikita Popov wrote:
> Hi internals, > > I would like to clarify how attributes are supposed to interact with > strict_types. Consider the following code, split up into three files to > make it clear that each one could have their own strict_types mode: > > MyAttribute.php > <?php > #[Attribute] > class MyAttribute { > public function __construct(string $a) {} > } > > UseOfMyAttribute.php > <?php > declare(strict_types=1); > #[MyAttribute(42)] > class Test {} > > AccessOfAttribute.php > <?php > var_dump((new > ReflectionClass(Test::class'))->getAttributes()[0]->newInstance()); > > Currently, what happens is that this code will construct the attribute, > converting int 42 into string "42", even though UseOfMyAttribute.php has > strict_types=1. > > My intuitive expectation here would be that we should be following the > strict_types mode of wherever the attribute is being used (i.e. > UseOfMyAttribute.php, not MyAttribute.php or AccessOfAttribute.php). > Currently, we always assume strict_types=0. > > Is my expectation correct? > > Regards, > Nikita
I could see an argument for either UseOfMyAttribute.php or AccessOfAttribute.php. I think I would also favor UseOfMyAttribute.php, however, because if you get it wrong the place you have to change it is in that file, so it should obey the setting in that file. --Larry Garfield

Benjamin Morel

5 years ago
I'd expect it to obey the strict_types declaration of UseOfMyAttribute.php, too. I see it as being where the attribute's constructor is "called", even though the actual object instantiation happens somewhere else. — Benjamin On Tue, 22 Sep 2020 at 16:11, Larry Garfield <larry@garfieldtech.com> wrote:

Nikita Popov

5 years ago
On Tue, Sep 22, 2020 at 2:58 PM Nikita Popov <nikita.ppv@gmail.com> wrote:
> Hi internals, > > I would like to clarify how attributes are supposed to interact with > strict_types. Consider the following code, split up into three files to > make it clear that each one could have their own strict_types mode: > > MyAttribute.php > <?php > #[Attribute] > class MyAttribute { > public function __construct(string $a) {} > } > > UseOfMyAttribute.php > <?php > declare(strict_types=1); > #[MyAttribute(42)] > class Test {} > > AccessOfAttribute.php > <?php > var_dump((new > ReflectionClass(Test::class'))->getAttributes()[0]->newInstance()); > > Currently, what happens is that this code will construct the attribute, > converting int 42 into string "42", even though UseOfMyAttribute.php has > strict_types=1. > > My intuitive expectation here would be that we should be following the > strict_types mode of wherever the attribute is being used (i.e. > UseOfMyAttribute.php, not MyAttribute.php or AccessOfAttribute.php). > Currently, we always assume strict_types=0. > > Is my expectation correct? > > Regards, > Nikita >
As we seem to have an agreement that strict_types of UseOfMyAttribute.php should be respected, I've created an implementation for this at https://github.com/php/php-src/pull/6201. Partway through I realized that the root problem is really that we want the constructor call to happen "as if" it was caused by the use-site of the attribute. This affects not just strict_types=1, but also backtrace and error information. In particular, this means that the backtrace now also points you to which attribute use-site resulted in an exception, which seems like rather useful information to have, as the same attribute might be used in many places. This does mean we have to store the line number of the attribute internally. We could also expose that information via ReflectionAttribute now, if we wanted. Regards, Nikita

Sara Golemon

5 years ago
On Tue, Sep 22, 2020 at 7:59 AM Nikita Popov <nikita.ppv@gmail.com> wrote:
> I would like to clarify how attributes are supposed to interact with > strict_types. Consider the following code, split up into three files to > make it clear that each one could have their own strict_types mode: > > MyAttribute.php > <?php > #[Attribute] > class MyAttribute { > public function __construct(string $a) {} > } > > UseOfMyAttribute.php > <?php > declare(strict_types=1); > #[MyAttribute(42)] > class Test {} > > AccessOfAttribute.php > <?php > var_dump((new > ReflectionClass(Test::class'))->getAttributes()[0]->newInstance()); > > Currently, what happens is that this code will construct the attribute, > converting int 42 into string "42", even though UseOfMyAttribute.php has > strict_types=1. > > My intuitive expectation here would be that we should be following the > strict_types mode of wherever the attribute is being used (i.e. > UseOfMyAttribute.php, not MyAttribute.php or AccessOfAttribute.php). > Currently, we always assume strict_types=0. > > Is my expectation correct? > >
I would say that your expectation is correct, and I'm willing to call the current behavior a bug. No need to worry about FF here. -Sara