-
Notifications
You must be signed in to change notification settings - Fork 25
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
PHP 8.2 Improvements #533
PHP 8.2 Improvements #533
Conversation
This reverts commit 525e918.
} | ||
} else { | ||
$head = $this->getElementsByTagName(Tag::HEAD)->item(0); | ||
if (!$head) { | ||
$this->head = $this->createElement(Tag::HEAD); | ||
$this->documentElement->insertBefore($this->head, $this->documentElement->firstChild); | ||
$this->properties['head'] = $this->createElement(Tag::HEAD); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not continue to use $this->head
and $this->body
? Is there a reason to switch to using $this->properties
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just for the sake of performance?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I ran into some issues when I originally tried that, but I might have been doing something wrong. I can give it another try 👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just tested again. Even on PHP 8.1 I am getting lots of Undefined property
warnings in this case.
Even when doing something seemingly simple like this:
// Throws warning
$this->html = $html;
return $this->html;
// Works
$this->html = $html;
return $html;
// Also works
$this->properties['html'] = $html;
return $this->properties['html'];
I also just analyzed the AmpProject\Dom\DocumentTest::testNormalizeDomStructure()
test case for this.
- Calling
normalizeDomStructure()
calls$this->head
- This triggers
__get()
- The getter for
head
runs, and it sees that it isn't set yet, which causes a call tonormalizeDomStructure()
again. The property hasn't been set yet. - That one then calls
moveInvalidHeadNodesToBody
at the end - That one then triggers
Undefined property: AmpProject\Dom\Document::$head
.
No such issues happen with the current $properties
approach.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the issue at question is this note:
PHP will not call an overloaded method from within the same overloaded method. That means, for example, writing return $this->foo inside of __get() will return null and raise an E_WARNING if there is no foo property defined, rather than calling __get() a second time. However, overload methods may invoke other overload methods implicitly (such as __set() triggering __get()).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In other words, if a caller is trying to access $x->foo
which invokes a magic getter, the getter must not also try to access $x->foo
although it can access $x->bar
. So there can't be any recursive reference to the current magic property being gotten.
Property `DOMElement::$tagName` is not nullable.
/** | ||
* Associative array for lazily-created, cached properties for the document. | ||
* | ||
* @var array | ||
*/ | ||
private $properties = []; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I just realized a potential large simplification here. Why if each of the properties were instead just declared as null?
/** | |
* Associative array for lazily-created, cached properties for the document. | |
* | |
* @var array | |
*/ | |
private $properties = []; | |
public $xpath | |
public $html; | |
public $head; | |
public $body; | |
public $charset; | |
public $viewport; | |
public $ampElements; | |
public $ampCustomStyle; | |
public $ampCustomStyleByteCount; | |
public $inlineStyleByteCount | |
public $links; |
The phpdoc notwithstanding.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see you did this in 525e918 but then reverted. Did you try private
instead of public
? This would model what is done with the $links
property already.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see the problem with that approach. It's that private access in the class won't cause the getter to be invoked. I think I have a way around that, and that is to manually invoke __get()
for methods on Document
. I'm going to give it a try, though the commit may not be pushed until Monday.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Bah. Doing this makes PHPStan blow up with a lot of "Access to private property" errors.
Co-authored-by: Jonny Harris <spacedmonkey@users.noreply.github.com>
This reverts commit 3d6cf89.
Fixes #532