On 16 July 2018 at 17:09, Larry Garfield <la...@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.



Regards,
-- 
Rowan Collins
[IMSoP]

Reply via email to