Re: [PHP-DEV] Constructor promoted property and default value

2023-10-25 Thread Robert Landers
On Mon, Oct 23, 2023 at 6:22 PM Pierre  wrote:
>
> Le 23/10/2023 à 18:11, Saki Takamachi a écrit :
> >> If I understand your use case properly, you should be confused by 
> >> properties with default values that are not constructor-promoted as well ? 
> >> Am I wrong ? In this case, your problem is not with promoted properties ?
> > If we specify it the way you say, the initial values of the constructor 
> > arguments will be available even when the constructor is not called.
> >
> > Such behavior felt a little counterintuitive.
>
> Which then would simply be the same behavior as properties when not
> promoted but declared in the class body instead:
>
> ```php
>
> class Foo
> {
>  public $val = 'abc';
> }
>
> $redis_foo = serialize(new Foo());
>
> $foo = unserialize($redis_foo);
> var_dump($foo->val);
> // string(3) "abc"
>
> ```
>
> Right ?
>
> What's the most disturbing in my opinion is that: `class Foo { public
> string $val = 'abc' }` and `class Foo { public function
> __construct(public string $val = 'abc' ) {}}` don't yield the same
> behavior at the time.
>
> Regards,
>
> --
>
> Pierre
>
> --
> PHP Internals - PHP Runtime Development Mailing List
> To unsubscribe, visit: https://www.php.net/unsub.php
>

Here's a nice and simple example:

https://3v4l.org/DU0tG

class A {
public string $default = 'default';
}

class B {
public function __construct(public string $default = 'default') {}
}

$a = new A();
echo "Original A: {$a->default}\n";
$b = new B();
echo "Original B: {$b->default}\n";

$a = (new ReflectionClass($a))->newInstanceWithoutConstructor();
echo "New A: {$a->default}\n";
$b = (new ReflectionClass($b))->newInstanceWithoutConstructor();
echo "New B: {$b->default}\n"; // crashes here

Robert Landers
Software Engineer
Utrecht NL

--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: https://www.php.net/unsub.php



Re: [PHP-DEV] Constructor promoted property and default value

2023-10-23 Thread Pierre

Le 23/10/2023 à 18:11, Saki Takamachi a écrit :

If I understand your use case properly, you should be confused by properties 
with default values that are not constructor-promoted as well ? Am I wrong ? In 
this case, your problem is not with promoted properties ?

If we specify it the way you say, the initial values ​​of the constructor 
arguments will be available even when the constructor is not called.

Such behavior felt a little counterintuitive.


Which then would simply be the same behavior as properties when not 
promoted but declared in the class body instead:


```php

class Foo
{
    public $val = 'abc';
}

$redis_foo = serialize(new Foo());

$foo = unserialize($redis_foo);
var_dump($foo->val);
// string(3) "abc"

```

Right ?

What's the most disturbing in my opinion is that: `class Foo { public 
string $val = 'abc' }` and `class Foo { public function 
__construct(public string $val = 'abc' ) {}}` don't yield the same 
behavior at the time.


Regards,

--

Pierre

--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: https://www.php.net/unsub.php



Re: [PHP-DEV] Constructor promoted property and default value

2023-10-23 Thread Saki Takamachi
> If I understand your use case properly, you should be confused by properties 
> with default values that are not constructor-promoted as well ? Am I wrong ? 
> In this case, your problem is not with promoted properties ?

If we specify it the way you say, the initial values ​​of the constructor 
arguments will be available even when the constructor is not called.

```
class Foo
{
public function __construct()
{
}
}

$foo = serialize(new Foo()); 
// save to redis

 update 

class Foo
{
public function __construct(
public $val = 'abc'
) {
}
}

$foo = unserialize($redis_foo);
var_dump($foo->val);
// string(3) "abc"
// Doesn't it look like the constructor is being called?
```

Such behavior felt a little counterintuitive.

Regards.

Saki

--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: https://www.php.net/unsub.php



Re: [PHP-DEV] Constructor promoted property and default value

2023-10-23 Thread Pierre

Le 23/10/2023 à 17:35, Saki Takamachi a écrit :

Hi, Pierre

You may have overlooked the existence of the magic method `__unserialize()`. 
Constructor is not the only way to create instances.

When rebuilding a serialized object, you may need the initial values ​​of 
properties. This can easily happen if you are using rolling updates and using 
Redis. The constructor is not called if `__unserialize()` is called. In this 
case, defining the initial value of a property as an argument to a constructor 
that is never called confuses us.

Regards.

Saki


If I understand your use case properly, you should be confused by 
properties with default values that are not constructor-promoted as well 
? Am I wrong ? In this case, your problem is not with promoted properties ?


Regards,

--

Pierre

--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: https://www.php.net/unsub.php



Re: [PHP-DEV] Constructor promoted property and default value

2023-10-23 Thread Saki Takamachi
Hi, Pierre

You may have overlooked the existence of the magic method `__unserialize()`. 
Constructor is not the only way to create instances.

When rebuilding a serialized object, you may need the initial values ​​of 
properties. This can easily happen if you are using rolling updates and using 
Redis. The constructor is not called if `__unserialize()` is called. In this 
case, defining the initial value of a property as an argument to a constructor 
that is never called confuses us.

Regards.

Saki
--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: https://www.php.net/unsub.php



Re: [PHP-DEV] Constructor promoted property and default value

2023-10-23 Thread Pierre

Le 23/10/2023 à 17:16, Larry Garfield a écrit :

Where this becomes a problem is readonly properties, since those are not 
allowed to have default values.  (That would make them constants with worse 
performance.)  A solution would need to be able to detect that the 
parent::__construct() isn't called, and then call it anyway, or at least 
partially call it.  Unfortunately, I can think of many cases where such a call 
would result in unexpected behavior.

It might be possible to resolve, but it's definitely not simple, and it could 
easily lead to weird behavior.

--Larry Garfield


Thanks for the explanation !

I see, there is no easy answer, yet current state is, in my opinion, 
unintuitive for developers, and eventually unsatisfying when falling in 
this trap.


That's sad that readonly properties make this not trivial. Maybe some 
kind of object construct-post-hook could detect those case and affect 
variables with default values ? I don't know enough PHP internals to 
give a rational answer to this problem through...


Regards,

--

Pierre



Re: [PHP-DEV] Constructor promoted property and default value

2023-10-23 Thread Larry Garfield
On Mon, Oct 23, 2023, at 2:18 PM, Pierre wrote:
> Hello internals,
>
> I stumbled upon this behavior, if I write this:
>
> ```php
> class Foo
> {
>      public ?string $prop = null;
>
>      public function __construct(?string $prop = null)
>      {
>      $this->prop = $prop;
>      }
> }
>
> class Bar extends Foo
> {
>      public function __construct(
>      public ?string $bar = null,
>      ) {}
> }
>
> // Echoes nothing, but it works as expected.
> echo (new Bar())->prop;
> ```
>
> It works as intended, but if I replace the `Foo` class using:
>
> ```php
> class Foo
> {
>      public function __construct(
>      public ?string $prop = null,
>      ) {}
> }
> ```
>
> It won't work anymore and I have the following error:
>
> ```
> PHP Warning:  Uncaught Error: Typed property Foo::$prop must not be 
> accessed before initialization in php shell code:9
> ```
>
> If I understand it correctly:
>   - in the first case, default value is attached to the object property, 
> so if I omit its constructor, I have the default,
>   - in the second case, default value is attached to the constructor 
> parameter, and not to the object property, which means that in case the 
> parent constructor is not called in the `Bar` class, `$prop` remains 
> initialized.
>
> It doesn't sound like a bug, but I think that many people would actually 
> expect otherwise: that the constructor promoted property keep their 
> default even when constructor is not explicitly called.
>
> Is there any good reason behind this ? Wouldn't it be best to change 
> this behavior ? Would it be a risk for backward compatibility (my guess 
> is "not that much, probably not a all even") ?

Where this becomes a problem is readonly properties, since those are not 
allowed to have default values.  (That would make them constants with worse 
performance.)  A solution would need to be able to detect that the 
parent::__construct() isn't called, and then call it anyway, or at least 
partially call it.  Unfortunately, I can think of many cases where such a call 
would result in unexpected behavior.

It might be possible to resolve, but it's definitely not simple, and it could 
easily lead to weird behavior.

--Larry Garfield

--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: https://www.php.net/unsub.php



[PHP-DEV] Constructor promoted property and default value

2023-10-23 Thread Pierre

Hello internals,

I stumbled upon this behavior, if I write this:

```php
class Foo
{
    public ?string $prop = null;

    public function __construct(?string $prop = null)
    {
    $this->prop = $prop;
    }
}

class Bar extends Foo
{
    public function __construct(
    public ?string $bar = null,
    ) {}
}

// Echoes nothing, but it works as expected.
echo (new Bar())->prop;
```

It works as intended, but if I replace the `Foo` class using:

```php
class Foo
{
    public function __construct(
    public ?string $prop = null,
    ) {}
}
```

It won't work anymore and I have the following error:

```
PHP Warning:  Uncaught Error: Typed property Foo::$prop must not be 
accessed before initialization in php shell code:9

```

If I understand it correctly:
 - in the first case, default value is attached to the object property, 
so if I omit its constructor, I have the default,
 - in the second case, default value is attached to the constructor 
parameter, and not to the object property, which means that in case the 
parent constructor is not called in the `Bar` class, `$prop` remains 
initialized.


It doesn't sound like a bug, but I think that many people would actually 
expect otherwise: that the constructor promoted property keep their 
default even when constructor is not explicitly called.


Is there any good reason behind this ? Wouldn't it be best to change 
this behavior ? Would it be a risk for backward compatibility (my guess 
is "not that much, probably not a all even") ?


Regards,

--
Pierre

--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: https://www.php.net/unsub.php