Dont icon indicating copy to clipboard operation
Dont copied to clipboard

Constructor Trait?

Open waknauss opened this issue 5 years ago • 8 comments

Hi, Would it be a good idea to have a trait that prevents the class constructor(s) from running more than once? I would be more than willing to code this up, I just have no idea what to call it.

waknauss avatar Nov 27 '20 02:11 waknauss

Probably DontInstantiate?

Ocramius avatar Nov 27 '20 09:11 Ocramius

So I've been rattling this one around in my brain, and I don't see how this is possible without setting a class property?

waknauss avatar Nov 29 '20 07:11 waknauss

Is it not possible to add a private ctor?

Ocramius avatar Nov 29 '20 11:11 Ocramius

I think we are talking about addressing two different things here.

Yes private constructors can be added.

I was referring to preventing a class constructor from executing more than once.

waknauss avatar Nov 30 '20 17:11 waknauss

I was referring to preventing a class constructor from executing more than once.

Ok, that is something I misread while scanning the notifications, sorry.

I think it can be done, but it's hard to do so without introducing more state in a class.

I would suggest going the easy way first: add a private property that is also marked @internal and you should be OK for now.

As for making it work with generic constructors, it becomes really tricky, but I've done it in ocramius/proxy-manager, and can be done through https://github.com/Ocramius/ProxyManager/blob/f65ae0f9dcbdd9d6ad3abb721a9e09c3d7d868a4/examples/access-interceptor-scope-localizer.php

Ocramius avatar Nov 30 '20 21:11 Ocramius

Here is how I see it going down. This is just pseudo code... Exceptions will be replaced with proper ones once I start coding.

@Ocramius - You are by far a better PHP programmer than me, so I wanted to check to see if this is what you had in mind?

<?php

declare(strict_types=1);

namespace Dont;

trait DontInstantiateTwice
{
    /**
     * constructorHasInited
     * Has the constructor inited?
     *
     * @var bool
     * @internal
     */
    private $constructorHasInited = false;

    private function initConstructor(): void 
    {
        if ($this->constructorHasInited===true)
        {
            throw Exception('reserved for future message');
        }

        $this->constructorHasInited = true;
    }
}

Pseudo Usage

<?php

use Dont\DontInstantiateTwice;

class Foo
{
    use DontInstantiateTwice;

    /**
     * __construct
     * Do some busy work
     * ...
     * 
     * @throws Exception - When the __construct is called more than once
     * per instantiated object
     */
    public function __construct()
    {
        //doing some busy work
        //...

        $this->initConstructor();
    }
}

waknauss avatar Dec 01 '20 20:12 waknauss

$this->initConstructor(); is not really defensive, since you can easily forget to call it.

vudaltsov avatar Feb 08 '21 16:02 vudaltsov

Agreed

Ocramius avatar Feb 08 '21 17:02 Ocramius