Re: Non-nullable properties
| From: | Christoph M. Becker | Date: | Thu, 19 Jul 2018 14:20:12 +0000 |
| Subject: | Re: Non-nullable properties | ||
| References: | 1 2 3 4 5 | Groups: | php.internals |
| Request: | Send a blank email to internals+get-102917@lists.php.net to get a copy of this message | ||
On 19.07.2018 at 15:41, Rowan Collins wrote:
> On 16 July 2018 at 17:09, Larry Garfield <larry@garfieldtech.com> wrote:
>
>> class Foo {
>>
>> protected Bar $b;
>>
>> // This runs before __construct, is not inherited, and cannot
>> // ever be skipped. If this method exits and any property is still
>> // value-less, TypeError immediately.
>> protected function __init() {
>> $this->b = new Bar();
>> }
>>
>> public function __construct() {
>> Behaves as it always has.
>> }
>> }
>>
>> That's similar to the "initialize" flag inside the constructor, but splits
>> it
>> off to a separate method that is devoted to just that purpose; it
>> therefore
>> has no parameters, ever, and if you want to initialize an object property
>> based on a constructor argument then you must either make it explicitly
>> nullable or initialize it to a dummy value first.
>
> The extra method certainly feels more "PHP-like" than an extra keyword, but
> as you say, calling it automatically makes it awkward to initialise based
> on any kind of input.
>
> A couple of variations on the theme:
>
> a) __init() takes the same arguments as __construct(), but is called first.
> This might be rather confusing, though - we could insist on the signatures
> matching, but people might be surprised that their constructor parameters
> are passed to their object twice in different methods.
>
> b) __init() is not called automatically, but has to be called manually,
> with whatever parameters you want, as the first line of __construct(). This
> feels a bit weird, because no other method name causes special behaviour
> when called manually. On the other hand, it allows it to be called in other
> situations, such as unserialize, which by-pass the constructor.
>
> A compromise system which doesn't need new keywords or magic would be to
> combine the current error-on-access behaviour with a check at the end of
> the constructor.
>
> So:
>
> = as soon as the constructor starts, $this is available as normal
> = accessing non-nullable properties of $this before initialising them would
> give an error (as in the current proposal)
> + when the constructor returns, the engine checks that all non-nullable
> properties have been correctly initialised, and immediately throws an error
> if they have not
> + Serializable#unserialize() could run the same check, since it is
> effectively a constructor
> = ReflectionClass#newInstanceWithoutConstructor could just allow the
> incomplete object, since such an object is not likely to work smoothly
> anyway
>
> Since $this can be passed to other functions and methods by the
> constructor, there is still a chance of code outside the class seeing an
> incomplete object and getting errors, but the distance between cause and
> effect (which is my main objection to the current proposal) is massively
> reduced.
It seems to me that either of these proposals would render the lazy
initialization pattern outlined in the “Overloaded Properties”
section[1] invalid.
[1] <https://wiki.php.net/rfc/typed_properties_v2#overloaded_properties>
--
Christoph M. Becker