spaze / phpstan-disallowed-calls

PHPStan rules to detect disallowed method & function calls, constant, namespace, attribute & superglobal usages
MIT License
255 stars 17 forks source link

Disallow calling constructor except from subclasses #144

Closed ruudk closed 1 year ago

ruudk commented 1 year ago

I'd like to protect an abstract class like this:

abstract class BaseError
{
    final public function __construct(public readonly string $code) {}
}

final class SomeError extends BaseError
{
    public static function create() : self
    {
        return new self('some');
    }
}

I know I can make the __constructor protected but I cannot use that at the moment.

Therefore, I'm looking for a way to prevent anybody from creating SomeError manually (e.g. new SomeError('test');).

Would be great if I could do this:

parameters:
    disallowedMethodCalls:
        -
            method: 'BaseError::__construct()'
            message: 'use public constructor instead'
            allowFromSubClass: true

It requires the rule to be able to know that the SomeError extends BaseError and therefore should match the config.

Would something like this be possible?

spaze commented 1 year ago

I'm not sure whether I'd like to add a flag like that, I thought you could solve it by disallowing BaseError::__construct() but allow it in BaseError::create() using allowInMethods, do you think it would work, at least theoretically? Because...

But when I went to verify the idea, I realized that when you disallow BaseClass::__construct(), calls like new ChildClass() are not reported which is a bug (works for regular methods, there's even a test for that). Filed #146 and added a (currently failing) test. I consider the issue a blocker for this issue no matter what we'll do here and how. I'll get back to this issue once that issue is fixed.

spaze commented 1 year ago

Starting with 2.11.2, you can now disallow a parent constructor and then allow it to be called in create() again. Please check this test to see the config https://github.com/spaze/phpstan-disallowed-calls/commit/b882fb222a425dc630c14154540f43558154dc94 and let me know if it helps your case. And if yes, I think you can close the issue :-)

ruudk commented 1 year ago

Sorry, didn't get back to you. Thanks for fixing. I just don't need it anymore as I sought another way to solve it. But I think some day in the future I will use it again.

spaze commented 1 year ago

Not a problem 😊 Thanks to this issue I've discovered and fixed another issue so all good 👍