Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Setting property default value to enum points to invalid namespace #754

Open
IonBazan opened this issue Mar 21, 2022 · 12 comments
Open

Setting property default value to enum points to invalid namespace #754

IonBazan opened this issue Mar 21, 2022 · 12 comments
Labels
bug dependencies Pull requests that update a dependency file

Comments

@IonBazan
Copy link

When generating a proxy where a default value is enum using PHP 8.1 (yes, I know...), the default value is missing leading slash, pointing to non-existent class.

namespace App\Domain\Transaction;

enum Status: string
{
    case INITIATED = 'INITIATED';
}
class Transaction
{
// ...
    protected Status $state = \App\Domain\Transaction\Status::INITIATED;
}

Generated proxy:

namespace MongoDBODMProxies\__PM__\App\Domain\Document\Transaction\Transaction;

class Generatedd19772223e8a9012106a186d3aa68e25 extends \App\Domain\Document\Transaction\Transaction implements \ProxyManager\Proxy\GhostObjectInterface
{
    private function callInitializer7e974($methodName, array $parameters)
    {
        if ($this->initializationTracker75370 || ! $this->initializer83563) {
            return;
        }

        $this->initializationTracker75370 = true;

        $this->state = App\Domain\Transaction\Status::INITIATED; // note missing leading backslash producing invalid namespace name
        // ...
    }
}

This is caused by var_export which implies root namespace, while generated proxy is its own namespace:

We could either explicitly check for enum_exists and prefix it with \ just to make things work but I'm not sure if it's right solution so just creating an issue to track this problem.

@Ocramius
Copy link
Owner

I think the reflection API does not give you default values for object types here.

The fact that a property can be an enum by default, without going through property initializers, seems like a hole in the RFC 🤔

I suggest raising a language bug.

@Ocramius
Copy link
Owner

Hmm, no, the reflection API works as expected: https://3v4l.org/jBhDg

@Ocramius
Copy link
Owner

The fact that var_export() operates this way makes it non-fixable here, because any constant expression composing over multiple constants would result in a problem.

For example:

var_export(['key' => Foo::BAR]);

I suggest proposing that the var_export() behaviour is to be fixed in php-src directly (for enums), so that it always refers to a FQCN, rather than a relative symbol.

@Ocramius
Copy link
Owner

Reported @ php/php-src#8232

@Ocramius Ocramius added bug dependencies Pull requests that update a dependency file labels Mar 21, 2022
Ocramius added a commit to Ocramius/php-src that referenced this issue Mar 21, 2022
This fix corrects a behavior of `var_export()` that was mostly "hidden" until PHP 8.1 introduced:

 * properties with object initializers
 * constants containing object references
 * default values of class properties containing `enum`s

Since `var_export(..., true)` is mostly used in conjunction with code generation,
and we cannot make assumptions about the generated code being placed in the root
namespace, we must always provide the FQCN of a class in exported code.

For example:

```php
<?php

namespace MyNamespace { class Foo {} }

namespace { echo "<?php\n\nnamespace Example;\n\n" . var_export(new \MyNamespace\Foo(), true) . ';'; }
```

produces:

```php
<?php

namespace Example;

MyNamespace\Foo::__set_state(array(
));
```

This code snippet is invalid, because `Example\MyNamespace\Foo::__set_state()` (which
does not exist) is called.

With this patch applied, the code looks like following (valid):

```php
<?php

namespace Example;

\MyNamespace\Foo::__set_state(array(
));
```

Ref: php#8232
Ref: Ocramius/ProxyManager#754
Ocramius added a commit to Ocramius/php-src that referenced this issue Mar 21, 2022
This fix corrects a behavior of `var_export()` that was mostly "hidden" until PHP 8.1 introduced:

 * properties with object initializers
 * constants containing object references
 * default values of class properties containing `enum`s

Since `var_export(..., true)` is mostly used in conjunction with code generation,
and we cannot make assumptions about the generated code being placed in the root
namespace, we must always provide the FQCN of a class in exported code.

For example:

```php
<?php

namespace MyNamespace { class Foo {} }

namespace { echo "<?php\n\nnamespace Example;\n\n" . var_export(new \MyNamespace\Foo(), true) . ';'; }
```

produces:

```php
<?php

namespace Example;

MyNamespace\Foo::__set_state(array(
));
```

This code snippet is invalid, because `Example\MyNamespace\Foo::__set_state()` (which
does not exist) is called.

With this patch applied, the code looks like following (valid):

```php
<?php

namespace Example;

\MyNamespace\Foo::__set_state(array(
));
```

Ref: php#8232
Ref: Ocramius/ProxyManager#754
Ocramius added a commit to Ocramius/php-src that referenced this issue Mar 21, 2022
This fix corrects a behavior of `var_export()` that was mostly "hidden" until PHP 8.1 introduced:

 * properties with object initializers
 * constants containing object references
 * default values of class properties containing `enum`s

Since `var_export(..., true)` is mostly used in conjunction with code generation,
and we cannot make assumptions about the generated code being placed in the root
namespace, we must always provide the FQCN of a class in exported code.

For example:

```php
<?php

namespace MyNamespace { class Foo {} }

namespace { echo "<?php\n\nnamespace Example;\n\n" . var_export(new \MyNamespace\Foo(), true) . ';'; }
```

produces:

```php
<?php

namespace Example;

MyNamespace\Foo::__set_state(array(
));
```

This code snippet is invalid, because `Example\MyNamespace\Foo::__set_state()` (which
does not exist) is called.

With this patch applied, the code looks like following (valid):

```php
<?php

namespace Example;

\MyNamespace\Foo::__set_state(array(
));
```

Ref: php#8232
Ref: Ocramius/ProxyManager#754
Ocramius added a commit to Ocramius/php-src that referenced this issue Mar 21, 2022
This fix corrects a behavior of `var_export()` that was mostly "hidden" until PHP 8.1 introduced:

* properties with object initializers
* constants containing object references
* default values of class properties containing `enum`s

Since `var_export(..., true)` is mostly used in conjunction with code generation,
and we cannot make assumptions about the generated code being placed in the root
namespace, we must always provide the FQCN of a class in exported code.

For example:

```php
<?php

namespace MyNamespace { class Foo {} }

namespace { echo "<?php\n\nnamespace Example;\n\n" . var_export(new \MyNamespace\Foo(), true) . ';'; }
```

produces:

```php
<?php

namespace Example;

MyNamespace\Foo::__set_state(array(
));
```

This code snippet is invalid, because `Example\MyNamespace\Foo::__set_state()` (which
does not exist) is called.

With this patch applied, the code looks like following (valid):

```php
<?php

namespace Example;

\MyNamespace\Foo::__set_state(array(
));
```

Ref: php#8232
Ref: Ocramius/ProxyManager#754
Ocramius added a commit to Ocramius/php-src that referenced this issue Mar 21, 2022
This fix corrects a behavior of `var_export()` that was mostly "hidden" until PHP 8.1 introduced:

* properties with object initializers
* constants containing object references
* default values of class properties containing `enum`s

Since `var_export(..., true)` is mostly used in conjunction with code generation,
and we cannot make assumptions about the generated code being placed in the root
namespace, we must always provide the FQCN of a class in exported code.

For example:

```php
<?php

namespace MyNamespace { class Foo {} }

namespace { echo "<?php\n\nnamespace Example;\n\n" . var_export(new \MyNamespace\Foo(), true) . ';'; }
```

produces:

```php
<?php

namespace Example;

MyNamespace\Foo::__set_state(array(
));
```

This code snippet is invalid, because `Example\MyNamespace\Foo::__set_state()` (which
does not exist) is called.

With this patch applied, the code looks like following (valid):

```php
<?php

namespace Example;

\MyNamespace\Foo::__set_state(array(
));
```

Ref: php#8232
Ref: Ocramius/ProxyManager#754
@Ocramius
Copy link
Owner

Ocramius commented Mar 21, 2022

Proposed upstream patch @ php/php-src#8233 - please review that, when you can :) EDIT: you already did, thanks!

Ocramius added a commit to Ocramius/doc-en that referenced this issue Mar 21, 2022
…ort()` docs

`var_export()` needs to prefix classes it references with `\`, because its code could be transplanted in
any source location/namespace, so the assumption of it being used only in the context of the root
namespace is not sufficient.

For example, in a code snippet like following ( https://3v4l.org/4mONc ):

```php
<?php

class SomeObject {}
var_export([new SomeObject]);
```

This should produce:

```
array (
  0 => 
  \SomeObject::__set_state(array(
  )),
)
```

Userland should not concern itself with the contents of the `var_export()`-produced code
snippets, and use them as-is instead.

Ref: php/php-src#8232
Ref: php/php-src#8233
Ref: Ocramius/ProxyManager#754
Ocramius added a commit to Ocramius/php-src that referenced this issue Mar 21, 2022
This fix corrects a behavior of `var_export()` that was mostly "hidden" until PHP 8.1 introduced:

* properties with object initializers
* constants containing object references
* default values of class properties containing `enum`s

Since `var_export(..., true)` is mostly used in conjunction with code generation,
and we cannot make assumptions about the generated code being placed in the root
namespace, we must always provide the FQCN of a class in exported code.

For example:

```php
<?php

namespace MyNamespace { class Foo {} }

namespace { echo "<?php\n\nnamespace Example;\n\n" . var_export(new \MyNamespace\Foo(), true) . ';'; }
```

produces:

```php
<?php

namespace Example;

MyNamespace\Foo::__set_state(array(
));
```

This code snippet is invalid, because `Example\MyNamespace\Foo::__set_state()` (which
does not exist) is called.

With this patch applied, the code looks like following (valid):

```php
<?php

namespace Example;

\MyNamespace\Foo::__set_state(array(
));
```

Ref: php#8232
Ref: Ocramius/ProxyManager#754
Ocramius added a commit to Ocramius/php-src that referenced this issue Mar 21, 2022
This fix corrects a behavior of `var_export()` that was mostly "hidden" until PHP 8.1 introduced:

* properties with object initializers
* constants containing object references
* default values of class properties containing `enum`s

Since `var_export(..., true)` is mostly used in conjunction with code generation,
and we cannot make assumptions about the generated code being placed in the root
namespace, we must always provide the FQCN of a class in exported code.

For example:

```php
<?php

namespace MyNamespace { class Foo {} }

namespace { echo "<?php\n\nnamespace Example;\n\n" . var_export(new \MyNamespace\Foo(), true) . ';'; }
```

produces:

```php
<?php

namespace Example;

MyNamespace\Foo::__set_state(array(
));
```

This code snippet is invalid, because `Example\MyNamespace\Foo::__set_state()` (which
does not exist) is called.

With this patch applied, the code looks like following (valid):

```php
<?php

namespace Example;

\MyNamespace\Foo::__set_state(array(
));
```

Ref: php#8232
Ref: Ocramius/ProxyManager#754
Ocramius added a commit to Ocramius/php-src that referenced this issue Mar 21, 2022
This fix corrects a behavior of `var_export()` that was mostly "hidden" until PHP 8.1 introduced:

* properties with object initializers
* constants containing object references
* default values of class properties containing `enum`s

Since `var_export(..., true)` is mostly used in conjunction with code generation,
and we cannot make assumptions about the generated code being placed in the root
namespace, we must always provide the FQCN of a class in exported code.

For example:

```php
<?php

namespace MyNamespace { class Foo {} }

namespace { echo "<?php\n\nnamespace Example;\n\n" . var_export(new \MyNamespace\Foo(), true) . ';'; }
```

produces:

```php
<?php

namespace Example;

MyNamespace\Foo::__set_state(array(
));
```

This code snippet is invalid, because `Example\MyNamespace\Foo::__set_state()` (which
does not exist) is called.

With this patch applied, the code looks like following (valid):

```php
<?php

namespace Example;

\MyNamespace\Foo::__set_state(array(
));
```

Ref: php#8232
Ref: Ocramius/ProxyManager#754
@IonBazan
Copy link
Author

image

@Ocramius
Copy link
Owner

Gonna be fixed in PHP 8.2: https://externals.io/message/117466#117532

Ref: php/php-src#8232
Ref: php/php-src#8233
Ref: php/doc-en#1472

@IonBazan
Copy link
Author

Sweet! @Ocramius

iluuu1994 pushed a commit to Ocramius/php-src that referenced this issue Apr 22, 2022
This fix corrects a behavior of `var_export()` that was mostly "hidden" until PHP 8.1 introduced:

* properties with object initializers
* constants containing object references
* default values of class properties containing `enum`s

Since `var_export(..., true)` is mostly used in conjunction with code generation,
and we cannot make assumptions about the generated code being placed in the root
namespace, we must always provide the FQCN of a class in exported code.

For example:

```php
<?php

namespace MyNamespace { class Foo {} }

namespace { echo "<?php\n\nnamespace Example;\n\n" . var_export(new \MyNamespace\Foo(), true) . ';'; }
```

produces:

```php
<?php

namespace Example;

MyNamespace\Foo::__set_state(array(
));
```

This code snippet is invalid, because `Example\MyNamespace\Foo::__set_state()` (which
does not exist) is called.

With this patch applied, the code looks like following (valid):

```php
<?php

namespace Example;

\MyNamespace\Foo::__set_state(array(
));
```

Ref: php#8232
Ref: Ocramius/ProxyManager#754
iluuu1994 pushed a commit to Ocramius/php-src that referenced this issue Apr 22, 2022
This fix corrects a behavior of `var_export()` that was mostly "hidden" until PHP 8.1 introduced:

* properties with object initializers
* constants containing object references
* default values of class properties containing `enum`s

Since `var_export(..., true)` is mostly used in conjunction with code generation,
and we cannot make assumptions about the generated code being placed in the root
namespace, we must always provide the FQCN of a class in exported code.

For example:

```php
<?php

namespace MyNamespace { class Foo {} }

namespace { echo "<?php\n\nnamespace Example;\n\n" . var_export(new \MyNamespace\Foo(), true) . ';'; }
```

produces:

```php
<?php

namespace Example;

MyNamespace\Foo::__set_state(array(
));
```

This code snippet is invalid, because `Example\MyNamespace\Foo::__set_state()` (which
does not exist) is called.

With this patch applied, the code looks like following (valid):

```php
<?php

namespace Example;

\MyNamespace\Foo::__set_state(array(
));
```

Ref: php#8232
Ref: Ocramius/ProxyManager#754
iluuu1994 pushed a commit to Ocramius/php-src that referenced this issue Apr 22, 2022
This fix corrects a behavior of `var_export()` that was mostly "hidden" until PHP 8.1 introduced:

* properties with object initializers
* constants containing object references
* default values of class properties containing `enum`s

Since `var_export(..., true)` is mostly used in conjunction with code generation,
and we cannot make assumptions about the generated code being placed in the root
namespace, we must always provide the FQCN of a class in exported code.

For example:

```php
<?php

namespace MyNamespace { class Foo {} }

namespace { echo "<?php\n\nnamespace Example;\n\n" . var_export(new \MyNamespace\Foo(), true) . ';'; }
```

produces:

```php
<?php

namespace Example;

MyNamespace\Foo::__set_state(array(
));
```

This code snippet is invalid, because `Example\MyNamespace\Foo::__set_state()` (which
does not exist) is called.

With this patch applied, the code looks like following (valid):

```php
<?php

namespace Example;

\MyNamespace\Foo::__set_state(array(
));
```

Ref: php#8232
Ref: Ocramius/ProxyManager#754
iluuu1994 pushed a commit to Ocramius/php-src that referenced this issue Apr 22, 2022
This fix corrects a behavior of `var_export()` that was mostly "hidden" until PHP 8.1 introduced:

* properties with object initializers
* constants containing object references
* default values of class properties containing `enum`s

Since `var_export(..., true)` is mostly used in conjunction with code generation,
and we cannot make assumptions about the generated code being placed in the root
namespace, we must always provide the FQCN of a class in exported code.

For example:

```php
<?php

namespace MyNamespace { class Foo {} }

namespace { echo "<?php\n\nnamespace Example;\n\n" . var_export(new \MyNamespace\Foo(), true) . ';'; }
```

produces:

```php
<?php

namespace Example;

MyNamespace\Foo::__set_state(array(
));
```

This code snippet is invalid, because `Example\MyNamespace\Foo::__set_state()` (which
does not exist) is called.

With this patch applied, the code looks like following (valid):

```php
<?php

namespace Example;

\MyNamespace\Foo::__set_state(array(
));
```

Ref: php#8232
Ref: Ocramius/ProxyManager#754
iluuu1994 pushed a commit to php/php-src that referenced this issue Apr 23, 2022
Closes GH-8233

This fix corrects a behavior of `var_export()` that was mostly "hidden" until PHP 8.1 introduced:

* properties with object initializers
* constants containing object references
* default values of class properties containing `enum`s

Since `var_export(..., true)` is mostly used in conjunction with code generation,
and we cannot make assumptions about the generated code being placed in the root
namespace, we must always provide the FQCN of a class in exported code.

For example:

```php
<?php

namespace MyNamespace { class Foo {} }

namespace { echo "<?php\n\nnamespace Example;\n\n" . var_export(new \MyNamespace\Foo(), true) . ';'; }
```

produces:

```php
<?php

namespace Example;

MyNamespace\Foo::__set_state(array(
));
```

This code snippet is invalid, because `Example\MyNamespace\Foo::__set_state()` (which
does not exist) is called.

With this patch applied, the code looks like following (valid):

```php
<?php

namespace Example;

\MyNamespace\Foo::__set_state(array(
));
```

Ref: #8232
Ref: Ocramius/ProxyManager#754
Ref: https://externals.io/message/117466
@nicolas-grekas
Copy link
Contributor

Enums don't work as defaults yet, but neither do objects as defaults.

The way to support both is to use the string representation of ReflectionPropery|ReflectionParameter since php/php-src#7540

Unfortunately the recent change on var_export might not help... 😅

@Ocramius
Copy link
Owner

Some partial support for this will come with PHP 8.2, as per:

@nicolas-grekas
Copy link
Contributor

nicolas-grekas commented Apr 27, 2022

FYI I'm making some experiments on FriendsOfPHP/proxy-manager-lts#17 to fix this issue and also add support for "new in initializers". I'll contribute back here if you think the approach I'm going to end up with would work for you.

@nicolas-grekas
Copy link
Contributor

Issue fixed on FriendsOfPHP/proxy-manager-lts, submitted here as #755

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug dependencies Pull requests that update a dependency file
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants