Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[CLEANUP] Fix Psalm warnings in AbstractHtmlProcessor #991

Merged
merged 3 commits into from
Apr 11, 2021

Conversation

oliverklee
Copy link
Contributor

No description provided.

@oliverklee oliverklee added this to the 6.0.0 milestone Apr 9, 2021
@oliverklee oliverklee requested a review from JakeQZ April 9, 2021 18:34
@oliverklee oliverklee self-assigned this Apr 9, 2021
Copy link
Contributor

@JakeQZ JakeQZ left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code changes look good. But for best forward compatibility (i.e. avoiding potentially having to make breaking changes in future) I think the constuctor should be protected and not final. Also a couple of minor issues/comments.


/**
* The constructor.
*
* Please use `::fromHtml` or `::fromDomDocument` instead.
*/
private function __construct()
final private function __construct()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wouldn't this prevent any extending class having a constructor at all? What if it needed one to perform some sort of initialization?

I actually think it would be more maintainable if the constructor is protected. That way, if any extending class needed a constructor, it could call the base class constructor. Then, if at some point in the future there was a need for the AbstractHtmlProcessor constructor to actually do anything, it wouldn't break extending classes that needed a constructor but had been unable to call the base class constructor (noting that, unlike C++, in PHP, base class constructors are not implicitly called if a constructor is defined in an extending class).

We have already encountered a similar issue with PHPUnit removing a constructor in a new major release (see #930 - they should have retained a do-nothing constructor to avoid the change being breaking).

I know that extensions of the class are not intended to be instantiated with new, and thus their constructors (if defined) should not be public. I appreciate that the idea behind this change is to prevent an extending class declaring a public constructor. However, it prevents an extending class declaring any constructor at all (AFAIK).

Copy link
Contributor Author

@oliverklee oliverklee Apr 11, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can make it protected, but we cannot drop the final or drop the constructor altogether. If we do any of these, Psalm (rightly) complains:

ERROR: UnsafeInstantiation - src/HtmlProcessor/AbstractHtmlProcessor.php:106:21 - Cannot safely instantiate class Pelago\Emogrifier\HtmlProcessor\AbstractHtmlProcessor with "new static" as its constructor might change in child classes (see https://psalm.dev/229)

        $instance = new static();

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In that case I think we should use the @psalm-consistent-constructor annotation so that child classes can have a constructor if needed, but, if so, Psalm would enforce that it has the same parameters (i.e. no parameters).

I also think the constructor should be protected but that's probably beyond the scope of this PR.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, changed accordingly.

protected function getXPath(): \DOMXPath
{
if (!$this->xPath instanceof \DOMXPath) {
throw new \BadMethodCallException('$this->xPath has not been initialized yet.', 1617819086);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we use self::class in the message (like for getDomDocument) rather than $this which might be a bit vague?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, we can! Changed and repushed.

@@ -60,16 +60,16 @@ abstract class AbstractHtmlProcessor
protected $domDocument = null;

/**
* @var \DOMXPath
* @var \DOMXPath|null
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we use @var ?\DOMXPath? It's a matter of style but the 'nullable' syntax is consistent with method signatures recognized by the PHP interpreter.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, this seems to work for Psalm. Changed.

@oliverklee oliverklee force-pushed the cleanup/psalm-abstract-html-processor branch 2 times, most recently from dc60718 to b0b0a0d Compare April 11, 2021 08:54
@oliverklee oliverklee requested a review from JakeQZ April 11, 2021 08:54
- use `?ClassName` instead of `ClassName|null` in annotations
- mention class names in exception messages from `getXpath()`
- make the constructor protected
@oliverklee oliverklee force-pushed the cleanup/psalm-abstract-html-processor branch from b0b0a0d to cc45c29 Compare April 11, 2021 15:30
@JakeQZ JakeQZ merged commit 2923bdf into main Apr 11, 2021
@JakeQZ JakeQZ deleted the cleanup/psalm-abstract-html-processor branch April 11, 2021 15:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants