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]